Skip to content

Commit

Permalink
Add init support for structure variable members being written, identi…
Browse files Browse the repository at this point in the history
…fied occasional recursion problem by struct members.
  • Loading branch information
mari-mari committed Jun 20, 2023
1 parent 3b71f4f commit 54cc7fd
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 27 deletions.
2 changes: 1 addition & 1 deletion decompiler/backend/cexpressiongenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from decompiler.structures.pseudo import Float, Integer, OperationType, Pointer, StringSymbol
from decompiler.structures.pseudo import instructions as instructions
from decompiler.structures.pseudo import operations as operations
from decompiler.structures.pseudo.operations import StructMember
from decompiler.structures.pseudo.operations import StructMemberAccess
from decompiler.structures.pseudo.typing import StructureType
from decompiler.structures.visitors.interfaces import DataflowObjectVisitorInterface

Expand Down
29 changes: 12 additions & 17 deletions decompiler/frontend/binaryninja/handlers/assignments.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Module implementing the AssignmentHandler for binaryninja."""
import logging
from functools import partial
from typing import Union

Expand All @@ -16,6 +17,7 @@
RegisterPair,
UnaryOperation,
)
from decompiler.structures.pseudo.operations import StructMemberAccess


class AssignmentHandler(Handler):
Expand Down Expand Up @@ -170,21 +172,14 @@ def lift_split_assignment(self, assignment: mediumlevelil.MediumLevelILSetVarSpl
def _lift_store_struct(self, instruction: mediumlevelil.MediumLevelILStoreStruct, **kwargs) -> Assignment:
"""Lift a MLIL_STORE_STRUCT_SSA instruction to pseudo (e.g. object->field = x)."""
vartype = self._lifter.lift(instruction.dest.expr_type)
return Assignment(
UnaryOperation(
OperationType.dereference,
[
BinaryOperation(
OperationType.plus,
[
UnaryOperation(OperationType.cast, [self._lifter.lift(instruction.dest)], vartype=Pointer(Integer.char())),
Constant(instruction.offset),
],
vartype=vartype,
),
],
vartype=Pointer(vartype),
writes_memory=instruction.dest_memory
),
self._lifter.lift(instruction.src),
struct_variable = self._lifter.lift(instruction.dest)
struct_member_access = StructMemberAccess(
src=struct_variable,
member_name=vartype.type.members.get(instruction.offset),
offset=instruction.offset,
operands=[struct_variable],
vartype=vartype,
writes_memory=instruction.dest_memory,
)
src = self._lifter.lift(instruction.src)
return Assignment(struct_member_access, src)
3 changes: 3 additions & 0 deletions decompiler/frontend/binaryninja/handlers/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ def lift_struct(self, struct: StructureType, **kwargs) -> PseudoStructureType:
return PseudoStructureType(tag_name=struct_name, members=members_dict, size=0)

def lift_struct_member(self, member: StructureMember) -> PseudoStructureMember:
# TODO handle the case when struct member is a pointer on the same struct
if isinstance(member.type, PointerType) and (isinstance(member.type.target, StructureType) or isinstance(member.type.target, NamedTypeReferenceType)):
return CustomType("SomeStructTemp", size=0)
return PseudoStructureMember(name=member.name, offset=member.offset, type=self._lifter.lift(member.type), size=0)

def lift_void(self, _, **kwargs) -> CustomType:
Expand Down
7 changes: 3 additions & 4 deletions decompiler/frontend/binaryninja/handlers/unary.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
Pointer,
UnaryOperation,
)
from decompiler.structures.pseudo.operations import StructMember
from decompiler.structures.pseudo.operations import StructMemberAccess
from decompiler.structures.pseudo.typing import StructureType


Expand Down Expand Up @@ -94,17 +94,16 @@ def _lift_zx_operation(self, instruction: MediumLevelILInstruction, **kwargs) ->
)
return self.lift_cast(instruction, **kwargs)

def _lift_load_struct(self, instruction: mediumlevelil.MediumLevelILLoadStruct, **kwargs) -> StructMember:
def _lift_load_struct(self, instruction: mediumlevelil.MediumLevelILLoadStruct, **kwargs) -> StructMemberAccess:
"""Lift a MLIL_LOAD_STRUCT_SSA (struct member access e.g. var#n->x) instruction."""
# TODO type of struct variable should be either ptr on struct or struct
# TODO type of the member hm actually we want member instance to know the struct type.
# TODO But it is not the same as vartype
# TODO check what happens if members values are changed
struct_variable = self._lifter.lift(instruction.src)
struct_ptr: Pointer = self._lifter.lift(instruction.src.expr_type)
struct_type: StructureType = struct_ptr.type
struct_member_name = struct_type.members.get(instruction.offset).name
return StructMember(src=struct_variable, vartype=struct_ptr, operands=[struct_variable], offset=instruction.offset, member_name=struct_member_name)
return StructMemberAccess(src=struct_variable, vartype=struct_ptr, operands=[struct_variable], offset=instruction.offset, member_name=struct_member_name)

def _lift_ftrunc(self, instruction: mediumlevelil.MediumLevelILFtrunc, **kwargs) -> UnaryOperation:
"""Lift a MLIL_FTRUNC operation."""
Expand Down
17 changes: 12 additions & 5 deletions decompiler/structures/pseudo/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ def accept(self, visitor: DataflowObjectVisitorInterface[T]) -> T:
return visitor.visit_unary_operation(self)


class StructMember(Operation):
class StructMemberAccess(Operation):
def __init__(
self,
src: Expression,
Expand All @@ -388,10 +388,11 @@ def __init__(
vartype: Type = UnknownType(),
writes_memory: Optional[int] = None,
):
super().__init__(OperationType.struct_member, operands, vartype, writes_memory)
super().__init__(OperationType.struct_member, operands, vartype)
self.struct_variable = src
self.member_offset = offset
self.member_name = member_name
self.writes_memory = writes_memory

def __str__(self):
return f"{self.struct_variable}->{self.member_name}"
Expand All @@ -404,21 +405,27 @@ def substitute(self, replacee: Expression, replacement: Expression) -> None:
self.struct_variable = replacement
self.operands[:] = [replacement]

def copy(self) -> StructMember:
def copy(self) -> StructMemberAccess:
"""Copy the current UnaryOperation, copying all operands and the type."""
return StructMember(
return StructMemberAccess(
self.struct_variable,
self.member_offset,
self.member_name,
[operand.copy() for operand in self._operands],
self._type.copy(),
# writes_memory=self._writes_memory,
writes_memory=self.writes_memory,
)

def accept(self, visitor: DataflowObjectVisitorInterface[T]) -> T:
"""Invoke the appropriate visitor for this Operation."""
return str(self)

def is_read_access(self):
return self.writes_memory is None

def is_write_access(self):
return self.writes_memory is not None


class BinaryOperation(Operation):
"""Class representing operations with two operands."""
Expand Down

0 comments on commit 54cc7fd

Please sign in to comment.