From ffafa54703d239414e616d88633736ced71b63a5 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Tue, 13 Dec 2022 22:46:39 -0500 Subject: Add instruction attributes to IL instructions --- python/highlevelil.py | 37 ++++++++++++++++++++++++++++++++++--- python/lowlevelil.py | 37 ++++++++++++++++++++++++++++++++++--- python/mediumlevelil.py | 37 ++++++++++++++++++++++++++++++++++--- 3 files changed, 102 insertions(+), 9 deletions(-) (limited to 'python') diff --git a/python/highlevelil.py b/python/highlevelil.py index ca6a8aaf..04ae68ff 100644 --- a/python/highlevelil.py +++ b/python/highlevelil.py @@ -20,13 +20,13 @@ import ctypes import struct -from typing import Optional, Generator, List, Union, NewType, Tuple, ClassVar, Mapping +from typing import Optional, Generator, List, Union, NewType, Tuple, ClassVar, Mapping, Set from dataclasses import dataclass from enum import Enum # Binary Ninja components from . import _binaryninjacore as core -from .enums import HighLevelILOperation, DataFlowQueryOption, FunctionGraphType +from .enums import HighLevelILOperation, DataFlowQueryOption, FunctionGraphType, ILInstructionAttribute from . import decorators from . import function from . import binaryview @@ -61,6 +61,7 @@ HighLevelILOperandType = Union['HighLevelILInstruction', 'lowlevelil.ILIntrinsic 'GotoLabel', databuffer.DataBuffer] VariablesList = List[Union['mediumlevelil.SSAVariable', 'variable.Variable']] StringOrType = Union[str, '_types.Type', '_types.TypeBuilder'] +ILInstructionAttributeSet = Union[Set[ILInstructionAttribute], List[ILInstructionAttribute]] class VariableReferenceType(Enum): @@ -117,6 +118,7 @@ class GotoLabel: @dataclass(frozen=True, order=True) class CoreHighLevelILInstruction: operation: HighLevelILOperation + attributes: int source_operand: int size: int operands: OperandsType @@ -127,7 +129,7 @@ class CoreHighLevelILInstruction: def from_BNHighLevelILInstruction(cls, instr: core.BNHighLevelILInstruction) -> 'CoreHighLevelILInstruction': operands: OperandsType = tuple([ExpressionIndex(instr.operands[i]) for i in range(5)]) # type: ignore return cls( - HighLevelILOperation(instr.operation), instr.sourceOperand, instr.size, operands, instr.address, + HighLevelILOperation(instr.operation), instr.attributes, instr.sourceOperand, instr.size, operands, instr.address, instr.parent ) @@ -644,6 +646,15 @@ class HighLevelILInstruction(BaseILInstruction): ) return None + @property + def attributes(self) -> Set[ILInstructionAttribute]: + """The set of optional attributes placed on the instruction""" + result: Set[ILInstructionAttribute] = set() + for flag in ILInstructionAttribute: + if self.core_instr.attributes & flag.value != 0: + result.add(flag) + return result + def get_possible_values(self, options: Optional[List[DataFlowQueryOption]] = None) -> 'variable.PossibleValueSet': mlil = self.mlil if mlil is None: @@ -2418,6 +2429,26 @@ class HighLevelILFunction: core.BNReplaceHighLevelILExpr(self.handle, original, new) + def set_expr_attributes(self, expr: InstructionOrExpression, value: ILInstructionAttributeSet): + """ + ``set_expr_attributes`` allows modification of instruction attributes but ONLY during lifting. + + .. warning:: This function should ONLY be called as a part of a lifter. It will otherwise not do anything useful as there's no way to trigger re-analysis of IL levels at this time. + + :param ExpressionIndex expr: the ExpressionIndex to replace (may also be an expression index) + :param set(ILInstructionAttribute) value: the set of attributes to place on the instruction + :rtype: None + """ + if isinstance(expr, HighLevelILInstruction): + expr = expr.expr_index + elif isinstance(expr, int): + expr = ExpressionIndex(expr) + + result = 0 + for flag in value: + result |= flag.value + core.BNSetHighLevelILExprAttributes(self.handle, expr, result) + def add_operand_list(self, operands: List[int]) -> ExpressionIndex: """ ``add_operand_list`` returns an operand list expression for the given list of integer operands. diff --git a/python/lowlevelil.py b/python/lowlevelil.py index 4a45514a..f1fb0c5f 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -20,11 +20,11 @@ import ctypes import struct -from typing import Generator, List, Optional, Dict, Union, Tuple, NewType, ClassVar +from typing import Generator, List, Optional, Dict, Union, Tuple, NewType, ClassVar, Set from dataclasses import dataclass # Binary Ninja components -from .enums import LowLevelILOperation, LowLevelILFlagCondition, DataFlowQueryOption, FunctionGraphType +from .enums import LowLevelILOperation, LowLevelILFlagCondition, DataFlowQueryOption, FunctionGraphType, ILInstructionAttribute from . import _binaryninjacore as core from . import basicblock #required for LowLevelILBasicBlock from . import function @@ -56,6 +56,7 @@ LowLevelILOperandType = Union['LowLevelILOperationAndSize', 'ILRegister', 'ILFla 'ILSemanticFlagClass', 'ILSemanticFlagGroup', 'LowLevelILFlagCondition', List[int], List['LowLevelILInstruction'], List[Union['ILFlag', 'ILRegister']], List['SSARegister'], List['SSARegisterStack'], List['SSAFlag'], List['SSARegisterOrFlag'], None] +ILInstructionAttributeSet = Union[Set[ILInstructionAttribute], List[ILInstructionAttribute]] class LowLevelILLabel: @@ -269,6 +270,7 @@ class LowLevelILOperationAndSize: @dataclass(frozen=True) class CoreLowLevelILInstruction: operation: LowLevelILOperation + attributes: int size: int flags: int source_operand: ExpressionIndex @@ -282,7 +284,7 @@ class CoreLowLevelILInstruction: ExpressionIndex(instr.operands[3]) ) return cls( - LowLevelILOperation(instr.operation), instr.size, instr.flags, instr.sourceOperand, operands, instr.address + LowLevelILOperation(instr.operation), instr.attributes, instr.size, instr.flags, instr.sourceOperand, operands, instr.address ) @@ -685,6 +687,15 @@ class LowLevelILInstruction(BaseILInstruction): result.append(LowLevelILOperationAndSize(self.instr.operation, self.instr.size)) return result + @property + def attributes(self) -> Set[ILInstructionAttribute]: + """The set of optional attributes placed on the instruction""" + result: Set[ILInstructionAttribute] = set() + for flag in ILInstructionAttribute: + if self.instr.attributes & flag.value != 0: + result.add(flag) + return result + @staticmethod def _make_options_array(options: Optional[List[DataFlowQueryOption]]): if options is None: @@ -3166,6 +3177,26 @@ class LowLevelILFunction: core.BNReplaceLowLevelILExpr(self.handle, original, new) + def set_expr_attributes(self, expr: InstructionOrExpression, value: ILInstructionAttributeSet): + """ + ``set_expr_attributes`` allows modification of instruction attributes but ONLY during lifting. + + .. warning:: This function should ONLY be called as a part of a lifter. It will otherwise not do anything useful as there's no way to trigger re-analysis of IL levels at this time. + + :param ExpressionIndex expr: the ExpressionIndex to replace (may also be an expression index) + :param set(ILInstructionAttribute) value: the set of attributes to place on the instruction + :rtype: None + """ + if isinstance(expr, LowLevelILInstruction): + expr = expr.expr_index + elif isinstance(expr, int): + expr = ExpressionIndex(expr) + + result = 0 + for flag in value: + result |= flag.value + core.BNSetLowLevelILExprAttributes(self.handle, expr, result) + def append(self, expr: ExpressionIndex) -> int: """ ``append`` adds the ExpressionIndex ``expr`` to the current LowLevelILFunction. diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 49c932f3..7280fb5e 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -21,12 +21,12 @@ from abc import abstractmethod import ctypes import struct -from typing import Optional, List, Union, Mapping, Generator, NewType, Tuple, ClassVar, Dict +from typing import Optional, List, Union, Mapping, Generator, NewType, Tuple, ClassVar, Dict, Set from dataclasses import dataclass # Binary Ninja components from . import _binaryninjacore as core -from .enums import MediumLevelILOperation, ILBranchDependence, DataFlowQueryOption, FunctionGraphType, DeadStoreElimination +from .enums import MediumLevelILOperation, ILBranchDependence, DataFlowQueryOption, FunctionGraphType, DeadStoreElimination, ILInstructionAttribute from . import basicblock from . import function from . import types @@ -58,6 +58,7 @@ MediumLevelILOperandType = Union[int, float, 'MediumLevelILOperationAndSize', 'M List['variable.Variable'], List['SSAVariable'], List['MediumLevelILInstruction'], Mapping[int, int]] StringOrType = Union[str, '_types.Type', '_types.TypeBuilder'] +ILInstructionAttributeSet = Union[Set[ILInstructionAttribute], List[ILInstructionAttribute]] @dataclass(frozen=True, repr=False, order=True) @@ -108,6 +109,7 @@ class MediumLevelILOperationAndSize: @dataclass(frozen=True) class CoreMediumLevelILInstruction: operation: MediumLevelILOperation + attributes: int source_operand: int size: int operands: OperandsType @@ -116,7 +118,7 @@ class CoreMediumLevelILInstruction: @classmethod def from_BNMediumLevelILInstruction(cls, instr: core.BNMediumLevelILInstruction) -> 'CoreMediumLevelILInstruction': operands: OperandsType = tuple([ExpressionIndex(instr.operands[i]) for i in range(5)]) # type: ignore - return cls(MediumLevelILOperation(instr.operation), instr.sourceOperand, instr.size, operands, instr.address) + return cls(MediumLevelILOperation(instr.operation), instr.attributes, instr.sourceOperand, instr.size, operands, instr.address) @dataclass(frozen=True) @@ -578,6 +580,15 @@ class MediumLevelILInstruction(BaseILInstruction): ) return None + @property + def attributes(self) -> Set[ILInstructionAttribute]: + """The set of optional attributes placed on the instruction""" + result: Set[ILInstructionAttribute] = set() + for flag in ILInstructionAttribute: + if self.instr.attributes & flag.value != 0: + result.add(flag) + return result + @staticmethod def _make_options_array(options: Optional[List[DataFlowQueryOption]]): if options is None: @@ -2901,6 +2912,26 @@ class MediumLevelILFunction: core.BNReplaceMediumLevelILExpr(self.handle, original, new) + def set_expr_attributes(self, expr: InstructionOrExpression, value: ILInstructionAttributeSet): + """ + ``set_expr_attributes`` allows modification of instruction attributes but ONLY during lifting. + + .. warning:: This function should ONLY be called as a part of a lifter. It will otherwise not do anything useful as there's no way to trigger re-analysis of IL levels at this time. + + :param ExpressionIndex expr: the ExpressionIndex to replace (may also be an expression index) + :param set(ILInstructionAttribute) value: the set of attributes to place on the instruction + :rtype: None + """ + if isinstance(expr, MediumLevelILInstruction): + expr = expr.expr_index + elif isinstance(expr, int): + expr = ExpressionIndex(expr) + + result = 0 + for flag in value: + result |= flag.value + core.BNSetMediumLevelILExprAttributes(self.handle, expr, result) + def append(self, expr: ExpressionIndex) -> int: """ ``append`` adds the ExpressionIndex ``expr`` to the current MediumLevelILFunction. -- cgit v1.3.1