diff --git a/chb/app/CHVersion.py b/chb/app/CHVersion.py index 5268ba73..f66fd295 100644 --- a/chb/app/CHVersion.py +++ b/chb/app/CHVersion.py @@ -1 +1 @@ -chbversion: str = "0.3.0-20250417" +chbversion: str = "0.3.0-20250420" diff --git a/chb/astinterface/ASTInterfaceBasicBlock.py b/chb/astinterface/ASTInterfaceBasicBlock.py index 866f0a41..5ee07e7d 100644 --- a/chb/astinterface/ASTInterfaceBasicBlock.py +++ b/chb/astinterface/ASTInterfaceBasicBlock.py @@ -361,6 +361,47 @@ def trampoline_payload_sideeffect_ast( return astree.mk_branch(cond, tr_stmt, estmt, "0x0") return tr_stmt + def trampoline_payload_compound_ast( + self, astree: "ASTInterface") -> AST.ASTStmt: + """ + compound condition: fallthrough / exit function (return): + B + B + B (fallthrough) + B set function return value + + ===> if (condition1 || condition2): + return (new return value) + fallthrough + + Note: recognition of return value not yet implemented. + """ + + bl3 = self.trampoline["payload-2"] + bl3instrs = sorted(bl3.instructions.items()) + if not len(bl3instrs) == 2: + return self.trampoline_payload_loop_ast(astree) + instr31 = bl3instrs[0][1] + if not instr31.mnemonic_stem == "MOV": + return self.trampoline_payload_loop_ast(astree) + instr32 = bl3instrs[1][1] + if not instr32.mnemonic_stem == "BX": + return self.trampoline_payload_loop_ast(astree) + + cond1 = self.trampoline_ast_condition("payload-0", astree) + cond2 = self.trampoline_ast_condition("payload-1", astree) + if cond1 is not None and cond2 is not None: + cond = astree.mk_binary_op("lor", cond1, cond2) + rstmt = astree.mk_return_stmt(None) + estmt = astree.mk_instr_sequence([]) + brstmt = astree.mk_branch(cond, rstmt, estmt, "0x0") + return brstmt + else: + chklogger.logger.error( + "Not all conditions resolved in compound trampoline condition: " + "cond1: %s; cond2: %s", str(cond1), str(cond2)) + return self.trampoline_payload_loop_ast(astree) + def trampoline_payload_loop_ast( self, astree: "ASTInterface") -> AST.ASTStmt: """Assumes a return via conditional POP.""" @@ -404,7 +445,7 @@ def trampoline_ast(self, astree: "ASTInterface") -> AST.ASTStmt: stmts.append(self.trampoline_setup_ast(astree)) if "payload-0" in self.trampoline or "payload" in self.trampoline: if len(self.trampoline_payload_roles) == 4: - stmts.append(self.trampoline_payload_loop_ast(astree)) + stmts.append(self.trampoline_payload_compound_ast(astree)) elif len(self.trampoline_payload_roles) == 3: stmts.append(self.trampoline_payload_sideeffect_ast(astree)) elif len(self.trampoline_payload_roles) == 1: diff --git a/chb/relational/CfgMatcher.py b/chb/relational/CfgMatcher.py index 3ed49bc1..e244e839 100644 --- a/chb/relational/CfgMatcher.py +++ b/chb/relational/CfgMatcher.py @@ -31,6 +31,8 @@ from chb.graphics.DotCfg import DotCfg import chb.util.fileutil as UF +from chb.util.loggingutil import chklogger + if TYPE_CHECKING: from chb.app.AppAccess import AppAccess @@ -290,7 +292,8 @@ def match_blockstrings(self) -> None: if b1 not in self.blockmapping: self._blockmapping[b1] = b2 elif self.blockmapping[b1] != b2: - print("Conflicting mapping (strings): " + b1 + ", " + b2) + chklogger.logger.warning( + "Conflicting mapping (strings): %s, %s", b1, b2) def match_blockcalls(self) -> None: for (s, (b1s, b2s)) in self._blockcalls.items(): @@ -300,7 +303,8 @@ def match_blockcalls(self) -> None: if b1 not in self.blockmapping: self._blockmapping[b1] = b2 elif self.blockmapping[b1] != b2: - print("Conflicting mapping (calls): " + b1 + ", " + b2) + chklogger.logger.warning( + "Conflicting mapping (calls): %s, %s", b1, b2) def match_branch_conditions(self) -> None: for (s, (b1s, b2s)) in self._blockbranches.items(): @@ -310,7 +314,8 @@ def match_branch_conditions(self) -> None: if b1 not in self.blockmapping: self._blockmapping[b1] = b2 elif self.blockmapping[b1] != b2: - print("Conflicting mapping (branches): " + b1 + ", " + b2) + chklogger.logger.warning( + "Conflicting mapping (branches): %s, %s", b1, b2) def match_edges(self) -> None: