summaryrefslogtreecommitdiff
path: root/python/examples
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2024-08-22 12:55:49 -0600
committerRusty Wagner <rusty.wagner@gmail.com>2024-10-21 13:56:55 -0400
commitd8e3001e535fad178c621ff07418f81f25123dc4 (patch)
tree54c03cef2f0bdfd9a3b6df4334c81becb63e4993 /python/examples
parent0e281a30d73c0f31ef9442fef0346779164231ad (diff)
Allow multiple high level representations for display, add Pseudo Rust and a Pseudo Python example plugin
Diffstat (limited to 'python/examples')
-rw-r--r--python/examples/pseudo_python.py1100
1 files changed, 1100 insertions, 0 deletions
diff --git a/python/examples/pseudo_python.py b/python/examples/pseudo_python.py
new file mode 100644
index 00000000..b68b4786
--- /dev/null
+++ b/python/examples/pseudo_python.py
@@ -0,0 +1,1100 @@
+# Copyright (c) 2024 Vector 35 Inc
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+from binaryninja import (Architecture, BraceRequirement, DisassemblySettings, DisassemblyTextLine, Function,
+ InstructionTextToken, InstructionTextTokenType, LanguageRepresentationFunction,
+ LanguageRepresentationFunctionType, HighLevelILInstruction, HighLevelILFunction,
+ HighLevelILTokenEmitter, HighLevelILOperation, OperatorPrecedence, ScopeType,
+ SymbolDisplayType, SymbolDisplayResult, SymbolType, BoolType, VoidType, PointerType,
+ NamedTypeReferenceType, StructureType, InstructionTextTokenContext, StructureMember,
+ BinaryView, BuiltinType)
+from typing import Optional
+import struct
+
+
+class PseudoPythonFunction(LanguageRepresentationFunction):
+ comment_start_string = "# "
+
+ def perform_init_token_emitter(self, emitter):
+ # Python never allows braces, even if the user has set the option to show them
+ emitter.brace_requirement = BraceRequirement.BracesNotAllowed
+
+ def perform_begin_lines(self, instr: HighLevelILInstruction, tokens: HighLevelILTokenEmitter):
+ # Ensure that the function body is indented relative to the function declaration
+ tokens.increase_indent()
+
+ def perform_get_expr_text(
+ self, instr: HighLevelILInstruction, tokens: HighLevelILTokenEmitter, settings: Optional[DisassemblySettings],
+ as_full_ast: bool = True, precedence: OperatorPrecedence = OperatorPrecedence.TopLevelOperatorPrecedence,
+ statement: bool = False
+ ):
+ with tokens.expr(instr):
+ if instr.operation == HighLevelILOperation.HLIL_BLOCK:
+ need_separator = False
+ body = instr.body
+ # Emit the lines for each statement in the body
+ for (idx, i) in enumerate(body):
+ # Don't display trailing return statements that don't have values
+ if (as_full_ast and idx + 1 == len(body) and i.operation == HighLevelILOperation.HLIL_RET and
+ len(i.src) == 0 and instr.expr_index == self.hlil.root.expr_index):
+ continue
+
+ # If the statement is one that contains additional blocks of code, insert a scope separator
+ # to visually separate the logic.
+ has_blocks = i.operation in [HighLevelILOperation.HLIL_IF, HighLevelILOperation.HLIL_WHILE,
+ HighLevelILOperation.HLIL_DO_WHILE, HighLevelILOperation.HLIL_FOR,
+ HighLevelILOperation.HLIL_SWITCH]
+ if need_separator or (idx != 0 and has_blocks):
+ tokens.scope_separator()
+ need_separator = has_blocks
+
+ # Emit the lines for the statement itself
+ self.perform_get_expr_text(i, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.new_line()
+ elif instr.operation == HighLevelILOperation.HLIL_IF:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "if "))
+ self.perform_get_expr_text(instr.condition, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, ":\n"))
+ if as_full_ast:
+ # Only display the if body when printing the full AST. When printing basic blocks in graph view,
+ # the body of the if and the else part are rendered as other nodes in the graph.
+ tokens.begin_scope(ScopeType.BlockScopeType)
+ self.perform_get_expr_text(instr.true, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.BlockScopeType)
+
+ # Else statements need to be handled as chains, since "else if" in Python should be rendered
+ # as "elif" statements.
+ if_chain = instr.false
+ while if_chain is not None and if_chain.operation not in [HighLevelILOperation.HLIL_NOP,
+ HighLevelILOperation.HLIL_UNREACHABLE]:
+ if if_chain.operation == HighLevelILOperation.HLIL_IF:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "elif "))
+ self.perform_get_expr_text(if_chain.condition, tokens, settings, as_full_ast)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ":"))
+ tokens.begin_scope(ScopeType.BlockScopeType)
+ self.perform_get_expr_text(if_chain.true, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.BlockScopeType)
+ if_chain = if_chain.false
+ else:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "else"))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ":"))
+ tokens.begin_scope(ScopeType.BlockScopeType)
+ self.perform_get_expr_text(if_chain, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.BlockScopeType)
+ break
+ elif instr.operation == HighLevelILOperation.HLIL_FOR:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "for "))
+
+ # If the for loop can be represented as a Python range function, show it that way
+ dest_var = None
+ if instr.init.operation == HighLevelILOperation.HLIL_VAR_INIT:
+ dest_var = instr.init.dest
+ elif instr.init.operation == HighLevelILOperation.HLIL_ASSIGN and instr.init.dest.operation == HighLevelILOperation.HLIL_VAR:
+ dest_var = instr.init.dest.var
+ if (dest_var is not None and
+ (instr.condition.operation in [HighLevelILOperation.HLIL_CMP_SLT,
+ HighLevelILOperation.HLIL_CMP_ULT]) and
+ instr.condition.left.operation == HighLevelILOperation.HLIL_VAR and
+ instr.condition.left.var == dest_var and
+ instr.update.operation == HighLevelILOperation.HLIL_ASSIGN and
+ instr.update.dest.operation == HighLevelILOperation.HLIL_VAR and
+ instr.update.dest.var == instr.condition.left.var and
+ instr.update.src.operation == HighLevelILOperation.HLIL_ADD and
+ instr.update.src.left.operation == HighLevelILOperation.HLIL_VAR and
+ instr.update.src.left.var == instr.condition.left.var):
+ step_by = (instr.update.src.right.operation != HighLevelILOperation.HLIL_CONST or
+ instr.update.src.right.constant != 1)
+ start_required = (instr.init.src.operation != HighLevelILOperation.HLIL_CONST or
+ instr.init.src.constant != 0 or step_by)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.LocalVariableToken, dest_var.name,
+ context=InstructionTextTokenContext.LocalVariableTokenContext,
+ address=instr.expr_index, value=dest_var.identifier,
+ size=instr.size))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, " in "))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "range"))
+ tokens.append_open_paren()
+ if start_required:
+ self.perform_get_expr_text(instr.init.src, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.condition.right, tokens, settings)
+ if step_by:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.update.src.right, tokens, settings)
+ tokens.append_close_paren()
+ else:
+ # Not representable directly as a Python loop, emit it with a more HLIL-like syntax
+ if instr.init.operation != HighLevelILOperation.HLIL_NOP:
+ self.perform_get_expr_text(instr.init, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, "; "))
+ if instr.condition.operation != HighLevelILOperation.HLIL_NOP:
+ self.perform_get_expr_text(instr.condition, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, "; "))
+ if instr.update.operation != HighLevelILOperation.HLIL_NOP:
+ self.perform_get_expr_text(instr.update, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, ":"))
+ tokens.begin_scope(ScopeType.BlockScopeType)
+ self.perform_get_expr_text(instr.body, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.BlockScopeType)
+ elif instr.operation == HighLevelILOperation.HLIL_WHILE:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "while "))
+ self.perform_get_expr_text(instr.condition, tokens, settings, as_full_ast)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, ":"))
+ tokens.begin_scope(ScopeType.BlockScopeType)
+ self.perform_get_expr_text(instr.body, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.BlockScopeType)
+ elif instr.operation == HighLevelILOperation.HLIL_DO_WHILE:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "do"))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, ":"))
+ tokens.begin_scope(ScopeType.BlockScopeType)
+ self.perform_get_expr_text(instr.body, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.BlockScopeType)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "while "))
+ self.perform_get_expr_text(instr.condition, tokens, settings, as_full_ast)
+ elif instr.operation == HighLevelILOperation.HLIL_SWITCH:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "match "))
+ self.perform_get_expr_text(instr.condition, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, ":"))
+ tokens.begin_scope(ScopeType.SwitchScopeType)
+
+ # Output each case
+ for case in instr.cases:
+ self.perform_get_expr_text(case, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.new_line()
+
+ # Check for default case
+ if instr.default is not None and instr.default.operation not in [HighLevelILOperation.HLIL_NOP,
+ HighLevelILOperation.HLIL_UNREACHABLE]:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "default"))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ":"))
+ tokens.begin_scope(ScopeType.CaseScopeType)
+ self.perform_get_expr_text(instr.default, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.CaseScopeType)
+ tokens.end_scope(ScopeType.SwitchScopeType)
+ elif instr.operation == HighLevelILOperation.HLIL_CASE:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "case "))
+ for (i, value) in enumerate(instr.values):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " | "))
+ self.perform_get_expr_text(value, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ":"))
+ tokens.begin_scope(ScopeType.CaseScopeType)
+ self.perform_get_expr_text(instr.body, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.CaseScopeType)
+ elif instr.operation == HighLevelILOperation.HLIL_BREAK:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "break"))
+ elif instr.operation == HighLevelILOperation.HLIL_CONTINUE:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "continue"))
+ elif instr.operation == HighLevelILOperation.HLIL_CALL:
+ self.perform_get_expr_text(instr.dest, tokens, settings, as_full_ast,
+ OperatorPrecedence.MemberAndFunctionOperatorPrecedence)
+ tokens.append_open_paren()
+ for (i, param) in enumerate(instr.params):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(param, tokens, settings)
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_TAILCALL:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "return "))
+ self.perform_get_expr_text(instr.dest, tokens, settings, as_full_ast,
+ OperatorPrecedence.MemberAndFunctionOperatorPrecedence)
+ tokens.append_open_paren()
+ for (i, param) in enumerate(instr.params):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(param, tokens, settings)
+ tokens.append_close_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, " # tailcall"))
+ elif instr.operation == HighLevelILOperation.HLIL_INTRINSIC:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, instr.intrinsic.name))
+ tokens.append_open_paren()
+ for (i, param) in enumerate(instr.params):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(param, tokens, settings)
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_SYSCALL:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "syscall"))
+ tokens.append_open_paren()
+ for (i, param) in enumerate(instr.params):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ if i == 0 and param.operation == HighLevelILOperation.HLIL_CONST:
+ platform = self.function.platform
+ if platform is not None:
+ syscall_name = platform.get_system_call_name(param.constant)
+ if len(syscall_name) > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, syscall_name))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, " "))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "{"))
+ self.perform_get_expr_text(param, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "}"))
+ continue
+ self.perform_get_expr_text(param, tokens, settings)
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_ZX:
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ elif instr.operation == HighLevelILOperation.HLIL_SX:
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ elif instr.operation == HighLevelILOperation.HLIL_IMPORT:
+ # Check for import address symbol at target address, and display that if there is one
+ sym = instr.function.source_function.view.get_symbol_at(instr.constant)
+ if sym is not None:
+ if sym.type == SymbolType.ImportedDataSymbol or sym.type == SymbolType.ImportAddressSymbol:
+ sym = sym.imported_function_from_import_address_symbol(instr.constant)
+ if sym is not None:
+ tokens.append(
+ InstructionTextToken(InstructionTextTokenType.IndirectImportToken, sym.short_name,
+ value=instr.constant, address=instr.address,
+ size=instr.size, operand=instr.source_operand))
+ return
+ # Otherwise use a generic pointer token
+ tokens.append_pointer_text_token(instr, instr.constant, settings,
+ SymbolDisplayType.DereferenceNonDataSymbols, precedence)
+ elif instr.operation == HighLevelILOperation.HLIL_ARRAY_INDEX:
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.MemberAndFunctionOperatorPrecedence)
+ tokens.append_open_bracket()
+ self.perform_get_expr_text(instr.index, tokens, settings)
+ tokens.append_close_bracket()
+ elif instr.operation == HighLevelILOperation.HLIL_VAR_INIT:
+ # Check to see if the variable appears live
+ appears_dead = False
+ ssa = instr.ssa_form
+ if ssa is not None and ssa.operation == HighLevelILOperation.HLIL_VAR_INIT_SSA:
+ appears_dead = not self.hlil.is_ssa_var_live(ssa.dest)
+
+ # If the variable does not appear live, show the assignment as zero confidence (grayed out)
+ with tokens.force_zero_confidence(appears_dead):
+ tokens.append_var_text_token(instr.dest, instr, instr.size)
+ if instr.dest.type is not None:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ": "))
+ tokens.append(instr.dest.type.get_tokens())
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " = "))
+
+ # For the right side of the assignment, only use zero confidence if the instruction does
+ # not have any side effects
+ with tokens.force_zero_confidence(appears_dead and not instr.src.has_side_effects):
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.AssignmentOperatorPrecedence)
+ elif instr.operation == HighLevelILOperation.HLIL_VAR_DECLARE:
+ tokens.append_var_text_token(instr.var, instr, instr.size)
+ if instr.var.type is not None:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ": "))
+ tokens.append(instr.var.type.get_tokens())
+ elif instr.operation == HighLevelILOperation.HLIL_FLOAT_CONST:
+ # The constant value in the instruction contains the raw bits of the floating point value. Convert
+ # this to a floating point value and display it.
+ if instr.size == 4:
+ value = struct.unpack("<f", struct.pack("<I", instr.constant))[0]
+ tokens.append(InstructionTextToken(InstructionTextTokenType.FloatToken, f"{value:g}"))
+ elif instr.size == 8:
+ value = struct.unpack("<d", struct.pack("<Q", instr.constant))[0]
+ tokens.append(InstructionTextToken(InstructionTextTokenType.FloatToken, f"{value:g}"))
+ else:
+ tokens.append_integer_text_token(instr, instr.constant, instr.size)
+ elif instr.operation == HighLevelILOperation.HLIL_CONST:
+ # Check for bool type. Display these as True or False. The default handling will use C style
+ # booleans instead of Python style.
+ if instr.size == 0 or isinstance(instr.expr_type, BoolType):
+ if instr.constant != 0:
+ tokens.append(
+ InstructionTextToken(InstructionTextTokenType.IntegerToken, "True", address=instr.address,
+ value=instr.constant))
+ else:
+ tokens.append(
+ InstructionTextToken(InstructionTextTokenType.IntegerToken, "False", address=instr.address,
+ value=instr.constant))
+ else:
+ tokens.append_constant_text_token(instr, instr.constant, instr.size, settings, precedence)
+ elif instr.operation == HighLevelILOperation.HLIL_CONST_PTR:
+ tokens.append_pointer_text_token(instr, instr.constant, settings,
+ SymbolDisplayType.AddressOfDataSymbols, precedence)
+ elif instr.operation == HighLevelILOperation.HLIL_CONST_DATA:
+ # Constant data should be rendered according to the type of builtin function being used.
+ data, builtin = instr.constant_data.data_and_builtin
+ if builtin in [BuiltinType.BuiltinStrcpy, BuiltinType.BuiltinStrncpy]:
+ data = data.escape(null_terminates=True)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.StringToken, f'"{data}"',
+ address=instr.address, value=instr.constant_data.value,
+ context=InstructionTextTokenContext.ConstStringDataTokenContext))
+ elif builtin == BuiltinType.BuiltinMemset:
+ tokens.append_open_brace()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.StringToken,
+ f"{instr.constant_data.value:#x}",
+ address=instr.address, value=instr.constant_data.value,
+ context=InstructionTextTokenContext.ConstDataTokenContext))
+ tokens.append_close_brace()
+ else:
+ string, string_type = self.function.view.stringify_unicode_data(self.function.arch, data)
+ if string is not None:
+ wide_string_prefix = ""
+ token_context = InstructionTextTokenContext.ConstDataTokenContext
+ if builtin == BuiltinType.BuiltinWcscpy:
+ wide_string_prefix = "L"
+ token_context = InstructionTextTokenContext.ConstStringDataTokenContext
+ tokens.append(InstructionTextToken(InstructionTextTokenType.StringToken,
+ f'{wide_string_prefix}"{string}"',
+ address=instr.address, value=instr.constant_data.value,
+ context=token_context))
+ else:
+ data = data.escape(null_terminates=False, escape_printable=True)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.StringToken, f'"{data}"',
+ address=instr.address, value=instr.constant_data.value,
+ context=InstructionTextTokenContext.ConstDataTokenContext))
+ elif instr.operation == HighLevelILOperation.HLIL_EXTERN_PTR:
+ # Extern pointer instructions have an offset associated with them. If this is nonzero, show this
+ # as an addition or subtraction of the offset.
+ parens = instr.offset != 0 and precedence >= OperatorPrecedence.AddOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ if instr.offset != 0:
+ precedence = OperatorPrecedence.SubOperatorPrecedence
+ tokens.append_pointer_text_token(instr, instr.constant, settings,
+ SymbolDisplayType.AddressOfDataSymbols, precedence)
+ if instr.offset < 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " - "))
+ tokens.append_integer_text_token(instr, -instr.offset, instr.size)
+ elif instr.offset > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " + "))
+ tokens.append_integer_text_token(instr, instr.offset, instr.size)
+
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_VAR:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.LocalVariableToken, instr.var.name,
+ address=instr.expr_index, size=instr.size,
+ value=instr.var.identifier,
+ context=InstructionTextTokenContext.LocalVariableTokenContext))
+ elif instr.operation == HighLevelILOperation.HLIL_ASSIGN:
+ # Check to see if the variable appears live
+ appears_dead = False
+ if instr.dest.operation == HighLevelILOperation.HLIL_VAR:
+ ssa = instr.ssa_form
+ if ssa is not None and ssa.operation == HighLevelILOperation.HLIL_VAR_INIT_SSA:
+ appears_dead = not self.hlil.is_ssa_var_live(ssa.dest)
+
+ # If the variable does not appear live, show the assignment as zero confidence (grayed out)
+ with tokens.force_zero_confidence(appears_dead):
+ self.perform_get_expr_text(instr.dest, tokens, settings, as_full_ast,
+ OperatorPrecedence.AssignmentOperatorPrecedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " = "))
+
+ # For the right side of the assignment, only use zero confidence if the instruction does
+ # not have any side effects
+ with tokens.force_zero_confidence(appears_dead and not instr.src.has_side_effects):
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.AssignmentOperatorPrecedence)
+ elif instr.operation == HighLevelILOperation.HLIL_ASSIGN_UNPACK:
+ tokens.append_open_paren()
+ for (i, dest) in enumerate(instr.dest):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(dest, tokens, settings)
+ tokens.append_close_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " = "))
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.AssignmentOperatorPrecedence)
+ elif instr.operation == HighLevelILOperation.HLIL_STRUCT_FIELD:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.MemberAndFunctionOperatorPrecedence)
+ self.append_field_text_tokens(instr.src, instr.offset, instr.member_index, instr.size, tokens)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_DEREF_FIELD:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ if instr.src.operation == HighLevelILOperation.HLIL_CONST_PTR:
+ tokens.append_pointer_text_token(instr.src, instr.src.constant, settings,
+ SymbolDisplayType.DisplaySymbolOnly,
+ OperatorPrecedence.MemberAndFunctionOperatorPrecedence)
+ else:
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.MemberAndFunctionOperatorPrecedence)
+ self.append_field_text_tokens(instr.src, instr.offset, instr.member_index, instr.size, tokens)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_DEREF:
+ if instr.src.operation == HighLevelILOperation.HLIL_CONST_PTR:
+ if tokens.append_pointer_text_token(instr.src, instr.src.constant, settings,
+ SymbolDisplayType.DereferenceNonDataSymbols,
+ precedence) == SymbolDisplayResult.DataSymbolResult:
+ expr_type = instr.src.expr_type
+ if isinstance(expr_type, PointerType) and expr_type.target.width != instr.size:
+ # If dereference size doesn't match the data variable size, append a size suffix
+ suffix = {0: "", 1: ".b", 2: ".w", 4: ".d", 8: ".q", 10: ".t", 16: ".q"}
+ if instr.size in suffix:
+ suffix_str = suffix[instr.size]
+ else:
+ suffix_str = f".{instr.size}"
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, suffix_str))
+ else:
+ parens = precedence > OperatorPrecedence.UnaryOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "*"))
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.UnaryOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_ADDRESS_OF:
+ parens = precedence > OperatorPrecedence.UnaryOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "&"))
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.UnaryOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_CMP_E, HighLevelILOperation.HLIL_FCMP_E]:
+ parens = precedence > OperatorPrecedence.EqualityOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings, as_full_ast,
+ OperatorPrecedence.EqualityOperatorPrecedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " == "))
+ self.perform_get_expr_text(instr.right, tokens, settings, as_full_ast,
+ OperatorPrecedence.EqualityOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_CMP_NE, HighLevelILOperation.HLIL_FCMP_NE]:
+ parens = precedence > OperatorPrecedence.EqualityOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings, as_full_ast,
+ OperatorPrecedence.EqualityOperatorPrecedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " != "))
+ self.perform_get_expr_text(instr.right, tokens, settings, as_full_ast,
+ OperatorPrecedence.EqualityOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_CMP_SLT, HighLevelILOperation.HLIL_CMP_ULT,
+ HighLevelILOperation.HLIL_FCMP_LT]:
+ parens = precedence > OperatorPrecedence.CompareOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " < "))
+ self.perform_get_expr_text(instr.right, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_CMP_SLE, HighLevelILOperation.HLIL_CMP_ULE,
+ HighLevelILOperation.HLIL_FCMP_LE]:
+ parens = precedence > OperatorPrecedence.CompareOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " <= "))
+ self.perform_get_expr_text(instr.right, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_CMP_SGE, HighLevelILOperation.HLIL_CMP_UGE,
+ HighLevelILOperation.HLIL_FCMP_GE]:
+ parens = precedence > OperatorPrecedence.CompareOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " >= "))
+ self.perform_get_expr_text(instr.right, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_CMP_SGT, HighLevelILOperation.HLIL_CMP_UGT,
+ HighLevelILOperation.HLIL_FCMP_GT]:
+ parens = precedence > OperatorPrecedence.CompareOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " > "))
+ self.perform_get_expr_text(instr.right, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_AND:
+ if instr.size == 0:
+ # Size of zero is a boolean operation, show the boolean operator name
+ parens = (precedence >= OperatorPrecedence.BitwiseOrOperatorPrecedence or
+ precedence == OperatorPrecedence.LogicalOrOperatorPrecedence)
+ operation = "and"
+ precedence = OperatorPrecedence.LogicalAndOperatorPrecedence
+ else:
+ parens = (precedence >= OperatorPrecedence.EqualityOperatorPrecedence or
+ precedence in [OperatorPrecedence.BitwiseOrOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ operation = "&"
+ precedence = OperatorPrecedence.BitwiseAndOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens(operation, instr, tokens, settings, as_full_ast, precedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_OR:
+ if instr.size == 0:
+ # Size of zero is a boolean operation, show the boolean operator name
+ parens = (precedence >= OperatorPrecedence.BitwiseOrOperatorPrecedence or
+ precedence == OperatorPrecedence.LogicalAndOperatorPrecedence)
+ operation = "or"
+ precedence = OperatorPrecedence.LogicalOrOperatorPrecedence
+ else:
+ parens = (precedence >= OperatorPrecedence.EqualityOperatorPrecedence or
+ precedence in [OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ operation = "|"
+ precedence = OperatorPrecedence.BitwiseOrOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens(operation, instr, tokens, settings, as_full_ast, precedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_XOR:
+ parens = (precedence >= OperatorPrecedence.EqualityOperatorPrecedence or
+ precedence in [OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseOrOperatorPrecedence])
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("^", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_ADC:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "adc"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.carry, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_SBB:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "sbb"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.carry, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_ADD_OVERFLOW:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "add_overflow"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_ADD, HighLevelILOperation.HLIL_FADD]:
+ parens = (precedence > OperatorPrecedence.AddOperatorPrecedence or
+ precedence in [OperatorPrecedence.ShiftOperatorPrecedence,
+ OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseOrOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("+", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.AddOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_SUB, HighLevelILOperation.HLIL_FSUB]:
+ parens = (precedence > OperatorPrecedence.AddOperatorPrecedence or
+ precedence in [OperatorPrecedence.ShiftOperatorPrecedence,
+ OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseOrOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("-", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.SubOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_MUL, HighLevelILOperation.HLIL_MULS_DP,
+ HighLevelILOperation.HLIL_MULU_DP, HighLevelILOperation.HLIL_FMUL]:
+ parens = (precedence > OperatorPrecedence.MultiplyOperatorPrecedence or
+ precedence in [OperatorPrecedence.ShiftOperatorPrecedence,
+ OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseOrOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("*", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.MultiplyOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_DIVS, HighLevelILOperation.HLIL_DIVU,
+ HighLevelILOperation.HLIL_DIVS_DP, HighLevelILOperation.HLIL_DIVU_DP]:
+ parens = (precedence > OperatorPrecedence.DivideOperatorPrecedence or
+ precedence in [OperatorPrecedence.ShiftOperatorPrecedence,
+ OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseOrOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("//", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.DivideOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_MODS, HighLevelILOperation.HLIL_MODU,
+ HighLevelILOperation.HLIL_MODS_DP, HighLevelILOperation.HLIL_MODU_DP]:
+ parens = (precedence > OperatorPrecedence.DivideOperatorPrecedence or
+ precedence in [OperatorPrecedence.ShiftOperatorPrecedence,
+ OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseOrOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("%", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.DivideOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_FDIV:
+ parens = (precedence > OperatorPrecedence.DivideOperatorPrecedence or
+ precedence in [OperatorPrecedence.ShiftOperatorPrecedence,
+ OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseOrOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("/", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.DivideOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_LSL:
+ parens = precedence > OperatorPrecedence.ShiftOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("<<", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.ShiftOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_LSR, HighLevelILOperation.HLIL_ASR]:
+ parens = precedence > OperatorPrecedence.ShiftOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens(">>", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.ShiftOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_ROL:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "rol"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_ROR:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "ror"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_RLC:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "rlc"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.carry, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_RRC:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "rrc"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.carry, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_TEST_BIT:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "test_bit"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_FLOOR:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "floor"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_CEIL:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "ceil"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_FTRUNC:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "trunc"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_FABS:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "fabs"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_FSQRT:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "sqrt"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_ROUND_TO_INT:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "round"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_FCMP_O:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "fcmp_o"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_FCMP_UO:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "fcmp_uo"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_NOT:
+ parens = precedence > OperatorPrecedence.UnaryOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ if instr.size == 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "not "))
+ else:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "~"))
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.UnaryOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_NEG, HighLevelILOperation.HLIL_FNEG]:
+ parens = precedence > OperatorPrecedence.UnaryOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "-"))
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.UnaryOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_FLOAT_CONV, HighLevelILOperation.HLIL_INT_TO_FLOAT]:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "float"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_FLOAT_TO_INT, HighLevelILOperation.HLIL_BOOL_TO_INT]:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "int"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_RET:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "return"))
+ operands = instr.src
+ if len(operands) > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, " "))
+ if len(operands) > 1:
+ tokens.append_open_paren()
+ for (i, operand) in enumerate(operands):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(operand, tokens, settings)
+ if len(operands) > 1:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_NORET:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "# no return"))
+ elif instr.operation == HighLevelILOperation.HLIL_UNREACHABLE:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "# unreachable"))
+ elif instr.operation == HighLevelILOperation.HLIL_UNDEF:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "# undefined"))
+ elif instr.operation == HighLevelILOperation.HLIL_NOP:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "# nop"))
+ elif instr.operation == HighLevelILOperation.HLIL_BP:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "breakpoint"))
+ tokens.append_open_paren()
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_JUMP:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "# jump -> "))
+ self.perform_get_expr_text(instr.dest, tokens, settings)
+ elif instr.operation == HighLevelILOperation.HLIL_TRAP:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "trap"))
+ tokens.append_open_paren()
+ tokens.append_integer_text_token(instr, instr.vector, 8)
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_GOTO:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "goto "))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.GotoLabelToken, instr.target.name,
+ instr.target.label_id))
+ elif instr.operation == HighLevelILOperation.HLIL_LABEL:
+ tokens.decrease_indent()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.GotoLabelToken, instr.target.name,
+ instr.target.label_id))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ":"))
+ tokens.increase_indent()
+ elif instr.operation == HighLevelILOperation.HLIL_LOW_PART:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ suffix = {0: "", 1: ".b", 2: ".w", 4: ".d", 8: ".q", 10: ".t", 16: ".q"}
+ if instr.size in suffix:
+ suffix_str = suffix[instr.size]
+ else:
+ suffix_str = f".{instr.size}"
+ tokens.append(InstructionTextToken(InstructionTextTokenType.StructOffsetToken, suffix_str, value=0,
+ size=instr.size))
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_SPLIT:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.high, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.low, tokens, settings)
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_UNIMPL, HighLevelILOperation.HLIL_UNIMPL_MEM]:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "# "))
+ for token in instr.tokens:
+ token.token_type = InstructionTextTokenType.AnnotationToken
+ tokens.append(token)
+ else:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken,
+ f"# unimplemented {instr.operation.name}"))
+
+ def append_two_operand_tokens(self, operation: str, instr: HighLevelILInstruction, tokens: HighLevelILTokenEmitter,
+ settings: Optional[DisassemblySettings], as_full_ast: bool,
+ precedence: OperatorPrecedence):
+ if precedence == OperatorPrecedence.SubOperatorPrecedence:
+ # Treat left side of subtraction as same level as addition. This lets
+ # (a - b) - c be represented as a - b - c, but a - (b - c) does not
+ # simplify at rendering
+ left_precedence = OperatorPrecedence.AddOperatorPrecedence
+ elif precedence == OperatorPrecedence.DivideOperatorPrecedence:
+ # Treat left side of divison as same level as multiplication. This lets
+ # (a / b) / c be represented as a / b / c, but a / (b / c) does not
+ # simplify at rendering
+ left_precedence = OperatorPrecedence.MultiplyOperatorPrecedence
+ else:
+ left_precedence = precedence
+
+ self.perform_get_expr_text(instr.left, tokens, settings, as_full_ast, left_precedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, f" {operation} "))
+ self.perform_get_expr_text(instr.right, tokens, settings, as_full_ast, precedence)
+
+ def append_field_text_tokens(self, var: HighLevelILInstruction, offset: int, member_index: int, size: int,
+ tokens: HighLevelILTokenEmitter):
+ var_type = var.expr_type
+ # Follow pointer type to its target
+ if isinstance(var_type, PointerType):
+ var_type = var_type.target
+ # Follow named type references to the target
+ if isinstance(var_type, NamedTypeReferenceType):
+ target_type = var_type.target(var.function.view)
+ if target_type is not None:
+ var_type = target_type
+
+ has_field = False
+ if isinstance(var_type, StructureType):
+ # For structures, resolve field names using the type API
+ class Resolver:
+ def __init__(self, view: BinaryView, offset: int):
+ self.has_field = False
+ self.correct_size = False
+ self.offset = offset
+ self.view = view
+
+ def resolve_func(self, base_name: Optional[NamedTypeReferenceType],
+ resolved_struct: Optional[StructureType], resolved_member_index: int,
+ struct_offset: int, adjusted_offset: int, member: StructureMember):
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "."))
+ name_list = HighLevelILTokenEmitter.names_for_outer_structure_members(
+ self.view, var_type, var) + [member.name]
+ tokens.append(InstructionTextToken(InstructionTextTokenType.FieldNameToken, member.name,
+ value=struct_offset + member.offset, typeNames=name_list))
+ self.offset = adjusted_offset - member.offset
+ self.has_field = True
+ self.correct_size = member.type is not None and size == member.type.width
+
+ resolver = Resolver(self.function.view, offset)
+ result = var_type.resolve_member_or_base_member(resolver.view, offset, 0, resolver.resolve_func)
+ if result and resolver.has_field and resolver.correct_size:
+ # If the field was matched, we're done
+ return
+ has_field = resolver.has_field
+ offset = resolver.offset
+
+ # Generate offset syntax for the missing field
+ suffix = {0: "", 1: ".b", 2: ".w", 4: ".d", 8: ".q", 10: ".t", 16: ".q"}
+ if size in suffix:
+ suffix_str = suffix[size]
+ else:
+ suffix_str = f".{size}"
+ if (has_field or not isinstance(var_type, StructureType)) and offset == 0:
+ # No offset, just display a size suffix
+ offset_str = suffix_str
+ else:
+ # Has an offset
+ offset_str = f".__offset({offset:#x}){suffix_str}"
+
+ name_list = HighLevelILTokenEmitter.names_for_outer_structure_members(
+ self.function.view, var_type, var) + [offset_str]
+ tokens.append(InstructionTextToken(InstructionTextTokenType.StructOffsetToken, offset_str, value=offset,
+ size=size, typeNames=name_list))
+
+
+class PseudoPythonFunctionType(LanguageRepresentationFunctionType):
+ language_name = "Pseudo Python"
+
+ def create(self, arch: Architecture, owner: Function, hlil: HighLevelILFunction):
+ return PseudoPythonFunction(arch, owner, hlil)
+
+ def function_type_tokens(self, func: Function, settings: DisassemblySettings) -> DisassemblyTextLine:
+ tokens = []
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "def "))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.CodeSymbolToken, func.name, value=func.start))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.BraceToken, "("))
+ for (i, param) in enumerate(func.type.parameters_with_all_locations):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.ArgumentNameToken, param.name,
+ context=InstructionTextTokenContext.LocalVariableTokenContext,
+ address=param.location.identifier))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ": "))
+ for token in param.type.get_tokens():
+ token.context = InstructionTextTokenContext.LocalVariableTokenContext
+ token.address = param.location.identifier
+ tokens.append(token)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.BraceToken, ")"))
+ if func.can_return.value and func.type.return_value is not None and not isinstance(func.type.return_value, VoidType):
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, " -> "))
+ for token in func.type.return_value.get_tokens():
+ token.context = InstructionTextTokenContext.FunctionReturnTokenContext
+ tokens.append(token)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ":"))
+ return [DisassemblyTextLine(tokens, func.start)]
+
+
+PseudoPythonFunctionType().register()