From f330547d4f0072c7d5f443c0dc43351cc1ccbf63 Mon Sep 17 00:00:00 2001 From: plasma-disassembler Date: Tue, 14 Nov 2017 21:24:14 +0100 Subject: [PATCH] visual: 'i' to invert conditional jumps in the decompilation mode --- README.md | 9 ++++----- images/invcond.png | Bin 0 -> 28473 bytes plasma/lib/ast.py | 5 +++-- plasma/lib/database.py | 10 +++++++++- plasma/lib/generate_ast.py | 21 ++++++++++++++------- plasma/lib/output.py | 2 ++ plasma/lib/ui/console.py | 1 + plasma/lib/ui/disasmbox.py | 28 ++++++++++++++++++++++++++++ 8 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 images/invcond.png diff --git a/README.md b/README.md index e67fbab..30d2765 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -PLASMA +PL**ASM**A ====== The old project name was **Reverse**. @@ -38,7 +38,7 @@ Optional : ./install.sh -Or if you have already installed requirements with the previous command : +Or if you have already installed requirements with the previous command: ./install.sh --update @@ -61,10 +61,9 @@ Check tests : ![plasma](/images/visual.png?raw=true) -## Qt memory map (memmap) +Take the control of the flow graph by inverting conditional jumps: -The image is actually static. -![plasma](/images/qt_memory.png?raw=true) +![plasma](/images/invcond.png?raw=true) ## Scripting (Python API) diff --git a/images/invcond.png b/images/invcond.png new file mode 100644 index 0000000000000000000000000000000000000000..ed9c5af5a8a101b38154ad50a95149043b99d97c GIT binary patch literal 28473 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 {addresses_with_xrefs: True} self.imports = {} # ad -> flags self.immediates = {} # insn_ad -> immediate result + self.inverted_cond = {} # addr -> arbitrary_value self.raw_base = 0 self.raw_type = None @@ -122,6 +123,7 @@ def load(self, filename): self.__load_xrefs(data) self.__load_imports(data) self.__load_immediates(data) + self.__load_inverted_cond(data) self.loaded = True @@ -151,6 +153,7 @@ def save(self, history): "raw_is_big_endian": self.raw_is_big_endian, "imports": self.imports, "immediates": self.immediates, + "inverted_cond": self.inverted_cond, } for j in self.jmptables.values(): @@ -253,3 +256,8 @@ def __load_functions(self, data): self.func_id_counter = data["func_id_counter"] except: self.func_id_counter = max(self.func_id.keys()) + 1 + + + def __load_inverted_cond(self, data): + if "inverted_cond" in data: + self.inverted_cond = data["inverted_cond"] diff --git a/plasma/lib/generate_ast.py b/plasma/lib/generate_ast.py index e5f2436..77067cd 100644 --- a/plasma/lib/generate_ast.py +++ b/plasma/lib/generate_ast.py @@ -446,6 +446,8 @@ def generate_ast(ctx__): fake_br = Ast_Branch() fake_br.level = sys.maxsize + libarch = ctx.gctx.libarch + while stack or waiting: if not stack and waiting: @@ -589,13 +591,13 @@ def generate_ast(ctx__): if c1: exit_loop = nxt[BRANCH_NEXT] nxt_node_in_loop = nxt[BRANCH_NEXT_JUMP] - cond_id = ctx.gctx.libarch.utils.invert_cond(blk[0]) + cond_id = libarch.utils.invert_cond(blk[0]) goto_set = True if c2: exit_loop = nxt[BRANCH_NEXT_JUMP] nxt_node_in_loop = nxt[BRANCH_NEXT] - cond_id = ctx.gctx.libarch.utils.get_cond(blk[0]) + cond_id = libarch.utils.get_cond(blk[0]) goto_set = True # goto to exit a loop @@ -614,7 +616,7 @@ def generate_ast(ctx__): # and-if if ctx.gctx.print_andif: if else_addr == nxt[BRANCH_NEXT_JUMP]: - cond_id = ctx.gctx.libarch.utils.invert_cond(blk[0]) + cond_id = libarch.utils.invert_cond(blk[0]) a = Ast_AndIf(blk[0], cond_id, nxt[BRANCH_NEXT], prefetch) a.parent = ast a.idx_in_parent = len(ast.nodes) @@ -636,7 +638,7 @@ def generate_ast(ctx__): # and-if if else_addr == nxt[BRANCH_NEXT]: - cond_id = ctx.gctx.libarch.utils.get_cond(blk[0]) + cond_id = libarch.utils.get_cond(blk[0]) a = Ast_AndIf(blk[0], cond_id, nxt[BRANCH_NEXT_JUMP], prefetch) a.parent = ast a.idx_in_parent = len(ast.nodes) @@ -654,6 +656,11 @@ def generate_ast(ctx__): endpoint = search_endpoint(ctx, ast, curr, l_set, l_prev_loop, l_start) + force_inv_if = False + if curr in ctx.gctx.db.inverted_cond: + nxt = list(reversed(nxt)) + force_inv_if = True + ast_if = Ast_Branch() ast_if.parent = ast ast_if.level = level + 1 @@ -706,7 +713,7 @@ def generate_ast(ctx__): ast.add(Ast_Goto(else_addr)) else: - a = Ast_Ifelse(blk[0], ast_else, ast_if, endpoint, prefetch) + a = Ast_Ifelse(blk[0], ast_else, ast_if, endpoint, prefetch, force_inv_if) stack.append((ast_else, list(loops_stack), curr, nxt[BRANCH_NEXT_JUMP], else_addr)) @@ -734,7 +741,7 @@ def generate_ast(ctx__): start = time() - for func in ctx.gctx.libarch.registered: + for func in libarch.registered: func(ctx, ast) elapsed = time() @@ -742,7 +749,7 @@ def generate_ast(ctx__): debug__("Functions for processing ast in %fs" % elapsed) if ctx.gctx.color: - assign_colors(ctx.gctx.libarch, ctx, ast) + assign_colors(libarch, ctx, ast) if waiting: ast_head.nodes.insert(0, Ast_Comment("")) diff --git a/plasma/lib/output.py b/plasma/lib/output.py index fd4455e..6817d9e 100644 --- a/plasma/lib/output.py +++ b/plasma/lib/output.py @@ -367,6 +367,8 @@ def _commented_inst(self, i, tab): self._bytes(i.bytes) self._comment(self.get_inst_str(i)) self._inline_comment(i) + if i.address in self.gctx.db.inverted_cond: + self._internal_comment(" ; manually inverted") self._new_line() diff --git a/plasma/lib/ui/console.py b/plasma/lib/ui/console.py index f8e8c7f..3cd0edc 100644 --- a/plasma/lib/ui/console.py +++ b/plasma/lib/ui/console.py @@ -282,6 +282,7 @@ def __init__(self, gctx): "; edit inline comment (enter/escape to validate/cancel)", "U undefine", "F list of functions", + "i decompilation: invert a conditional jump", "", "Options:", "I switch to traditional instruction string output (3 modes)", diff --git a/plasma/lib/ui/disasmbox.py b/plasma/lib/ui/disasmbox.py index 58156a9..4ffda93 100644 --- a/plasma/lib/ui/disasmbox.py +++ b/plasma/lib/ui/disasmbox.py @@ -113,6 +113,7 @@ def __init__(self, x, y, w, h, gctx, ad, analyzer, api, b"N": self.main_cmd_search_backward, b"j": self.main_cmd_jump_to, b"F": self.main_cmd_functions, + b"i": self.main_cmd_invert_conf, b"c": self.main_cmd_set_code, b"p": self.main_cmd_set_function, @@ -1314,3 +1315,30 @@ def main_cmd_functions(self): self.goto_address(ad) self.main_cmd_line_middle() return ret + + + def main_cmd_invert_conf(self): + if self.mode != MODE_DECOMPILE: + self.status_bar_message("only if decompilation mode") + return False + + line = self.win_y + self.cursor_y + if line not in self.output.line_addr: + self.status_bar_message("error: move the cursor on a conditional jump") + return False + + ad = self.output.line_addr[line] + + i = self.gctx.dis.lazy_disasm(ad) + if i is not None and not self.gctx.libarch.utils.is_cond_jump(i): + self.status_bar_message("error: move the cursor on a conditional jump") + return False + + if ad in self.db.inverted_cond: + del self.db.inverted_cond[ad] + else: + self.db.inverted_cond[ad] = 1 + + self.reload_asm() + self.db.modified = True + return True