Permalink
Browse files

Initial import

  • Loading branch information...
0 parents commit 92e679a4d5a369568f924c193911ec3ee35d8f97 @nelhage committed Dec 27, 2010
Showing with 393 additions and 0 deletions.
  1. +21 −0 COPYING
  2. +180 −0 ddx.el
  3. +192 −0 ddx2dot
21 COPYING
@@ -0,0 +1,21 @@
+Reverse Android -- some miscellaneous Android reverse-engineering tools.
+Copyright (c) 2010 Nelson Elhage
+
+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.
180 ddx.el
@@ -0,0 +1,180 @@
+(defconst ddx-dex-opcode-list
+ (list
+ "nop" "move" "move/from16" "move/16"
+ "move-wide" "move-wide/from16" "move-wide/16" "move-object"
+ "move-object/from16" "move-object/16" "move-result" "move-result-wide"
+ "move-result-object" "move-exception" "return-void" "return"
+ "return-wide" "return-object" "const/4" "const/16"
+ "const" "const/high16" "const-wide/16" "const-wide/32"
+ "const-wide" "const-wide/high16" "const-string" "const-string/jumbo"
+ "const-class" "monitor-enter" "monitor-exit" "check-cast"
+ "instance-of" "array-length" "new-instance" "new-array"
+ "filled-new-array" "filled-new-array/range" "fill-array-data" "throw"
+ "goto" "goto/16" "goto/32" "packed-switch"
+ "sparse-switch" "cmpl-float"
+ "cmpg-float" "cmpl-double" "cmpg-double" "cmp-long"
+ "if-eq" "if-ne"
+ "if-lt" "if-ge" "if-gt" "if-le"
+ "if-" "z" "if-eqz" "if-nez"
+ "if-ltz" "if-gez" "if-gtz" "if-lez"
+ "aget" "aget-wide" "aget-object"
+ "aget-boolean" "aget-byte" "aget-char" "aget-short"
+ "aput" "aput-wide" "aput-object" "aput-boolean"
+ "aput-byte" "aput-char" "aput-short"
+ "iget" "iget-wide" "iget-object"
+ "iget-boolean" "iget-byte" "iget-char" "iget-short"
+ "iput" "iput-wide" "iput-object" "iput-boolean"
+ "iput-byte" "iput-char" "iput-short"
+ "sget" "sget-wide" "sget-object"
+ "sget-boolean" "sget-byte" "sget-char" "sget-short"
+ "sput" "sput-wide" "sput-object" "sput-boolean"
+ "sput-byte" "sput-char" "sput-short"
+ "invoke-virtual" "invoke-super" "invoke-direct"
+ "invoke-static" "invoke-interface" "invoke-" "/range"
+ "invoke-virtual/range" "invoke-super/range" "invoke-direct/range" "invoke-static/range"
+ "invoke-interface/range" "neg-int" "not-int"
+ "neg-long" "not-long" "neg-float" "neg-double"
+ "int-to-long" "int-to-float" "int-to-double" "long-to-int"
+ "long-to-float" "long-to-double" "float-to-int" "float-to-long"
+ "float-to-double" "double-to-int" "double-to-long" "double-to-float"
+ "int-to-byte" "int-to-char" "int-to-short"
+ "add-int" "sub-int" "mul-int" "div-int"
+ "rem-int" "and-int" "or-int" "xor-int"
+ "shl-int" "shr-int" "ushr-int" "add-long"
+ "sub-long" "mul-long" "div-long" "rem-long"
+ "and-long" "or-long" "xor-long" "shl-long"
+ "shr-long" "ushr-long" "add-float" "sub-float"
+ "mul-float" "div-float" "rem-float" "add-double"
+ "sub-double" "mul-double" "div-double" "rem-double"
+ "/2addr" "add-int/2addr" "sub-int/2addr" "mul-int/2addr"
+ "div-int/2addr" "rem-int/2addr" "and-int/2addr" "or-int/2addr"
+ "xor-int/2addr" "shl-int/2addr" "shr-int/2addr" "ushr-int/2addr"
+ "add-long/2addr" "sub-long/2addr" "mul-long/2addr" "div-long/2addr"
+ "rem-long/2addr" "and-long/2addr" "or-long/2addr" "xor-long/2addr"
+ "shl-long/2addr" "shr-long/2addr" "ushr-long/2addr" "add-float/2addr"
+ "sub-float/2addr" "mul-float/2addr" "div-float/2addr" "rem-float/2addr"
+ "add-double/2addr" "sub-double/2addr" "mul-double/2addr" "div-double/2addr"
+ "rem-double/2addr" "/lit16" "add-int/lit16" "rsub-int"
+ "mul-int/lit16" "div-int/lit16" "rem-int/lit16" "and-int/lit16"
+ "or-int/lit16" "xor-int/lit16" "/lit8" "add-int/lit8"
+ "rsub-int/lit8" "mul-int/lit8" "div-int/lit8" "rem-int/lit8"
+ "and-int/lit8" "or-int/lit8" "xor-int/lit8" "shl-int/lit8"
+ "shr-int/lit8" "ushr-int/lit8"))
+
+(defvar ddx-mode-font-lock-keywords
+ (list
+ (cons (concat "\\<" (regexp-opt ddx-dex-opcode-list) "\\>")
+ font-lock-builtin-face)
+ (cons (concat "\\<" (regexp-opt '("private" "public" "static" "final")) "\\>")
+ font-lock-keyword-face)
+ (cons "[#;].*" font-lock-comment-face)
+ (cons (concat "\\.\\<" (regexp-opt '("field" "method" "limit"
+ "throws" "catch" "class"
+ "super" "var" "line"
+ "registers" "annotation"
+ "end")) "\\>")
+ font-lock-preprocessor-face)
+ (cons "^\\sw+:" font-lock-constant-face)
+ (cons "\\<[vp][[:digit:]]+\\>" font-lock-variable-name-face)))
+
+(defvar ddx-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "M-.") 'ddx-goto-label)
+ map)
+ "Keymap for DDX major mode")
+
+(defvar ddx-mode-syntax-table
+ (let ((tbl (make-syntax-table)))
+ (modify-syntax-entry ?_ "w" tbl)
+ (modify-syntax-entry ?\; "<" tbl)
+ (modify-syntax-entry ?\n ">" tbl)
+ tbl))
+
+(defun ddx-goto-label (&optional label)
+ (interactive)
+ (if (not label)
+ (setq label (thing-at-point 'word)))
+ (beginning-of-buffer)
+ (re-search-forward (concat "^" label ":")))
+
+(defface ddx-label-highlight
+ '((t :background "#003"))
+ "Face to highlabel selected label in ddx-mode")
+
+(set-face-background 'ddx-label-highlight "#33a")
+
+(defun ddx-highlight-label (label)
+ (interactive)
+ (save-excursion
+ (beginning-of-buffer)
+ (while (re-search-forward (concat "\\<" label "\\>") nil t)
+ (let ((start (match-beginning 0))
+ (end (match-end 0)))
+ (let ((ov (make-overlay start end)))
+ (overlay-put ov 'ddx-label-highlight t)
+ (overlay-put ov 'face 'ddx-label-highlight))))))
+
+(defun ddx-remove-highlights ()
+ (interactive)
+ (remove-overlays (point-min) (point-max) 'ddx-label-highlight t))
+
+(defvar ddx-highlighted-label nil
+ "The currently-highlighted label")
+
+(defvar ddx-all-labels nil
+ "All labels in the current buffer")
+
+(defun ddx-collect-labels ()
+ (set (make-local-variable 'ddx-all-labels)
+ (make-hash-table :test 'equal))
+ (save-excursion
+ (beginning-of-buffer)
+ (while (re-search-forward "^\\(\\sw+\\):" nil t)
+ (let ((l (match-string-no-properties 1)))
+ (puthash l t ddx-all-labels)))))
+
+(defun ddx-label-at-point ()
+ (let ((l (thing-at-point 'word)))
+ (set-text-properties 0 (length l) nil l)
+ (if (gethash l ddx-all-labels) l nil)))
+
+(defun ddx-highlight-current-label ()
+ (let ((l (ddx-label-at-point)))
+ (when (not (equal l ddx-highlighted-label))
+ (ddx-remove-highlights)
+ (if l (ddx-highlight-label l))
+ (setq ddx-highlighted-label l))))
+
+(defun ddx-timer-highlight ()
+ (save-match-data
+ (ddx-highlight-current-label)))
+
+(defvar ddx-idle-timer nil)
+
+(defun ddx-reset-timer ()
+ (if ddx-idle-timer (cancel-timer ddx-idle-timer))
+ (setq ddx-idle-timer
+ (run-with-idle-timer 0.1 t 'ddx-timer-highlight)))
+
+(define-derived-mode ddx-mode fundamental-mode "DDX"
+ "Major mode to edit decompiled DEX files."
+ (set (make-local-variable 'font-lock-defaults)
+ '(ddx-mode-font-lock-keywords))
+ (use-local-map ddx-mode-map)
+ (set-syntax-table ddx-mode-syntax-table)
+ (set (make-local-variable 'ddx-highlighted-label) nil)
+ (ddx-collect-labels)
+ (ddx-reset-timer)
+ (require 'javadoc))
+
+(add-to-list 'auto-mode-alist (cons "\\.ddx$" 'ddx-mode))
+
+(defmacro save-match-data (&rest body)
+ "Execute BODY, preserving any pre-existing match data"
+ (let ((v (gensym)))
+ `(let ((,v (match-data)))
+ (unwind-protect
+ (progn ,@body)
+ (set-match-data ,v)))))
+
+(provide 'ddx)
192 ddx2dot
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+import os
+import sys
+import re
+import os.path
+import pydot
+
+# pydot has horrible quoting bugs. Monkey-patch away their quoting
+# infrastructure with our own.
+
+class QuotedString(str):
+ """A string that has already been quoted for dot.
+
+ pydot assumes that it can quote a string multiple times and the
+ second and future calls will be no-ops. We implement this using a
+ simple subclass of `str' that lets us know we've already quoted
+ this string.
+ """
+ pass
+
+def do_quote(s):
+ if isinstance(s, QuotedString):
+ return s
+ if not isinstance(s, basestring):
+ return s
+
+ s = s.replace(' ', r'\ ').replace('"', r'\"')
+
+ return QuotedString('"%s"' % (s,))
+
+pydot.quote_if_necessary = do_quote
+
+def as_html(lines):
+ if not lines:
+ return ""
+ out = []
+ out.append('<<table border="0" cellborder="0" align="left">')
+ for line in lines:
+ out.append('<tr><td align="left">')
+ out.append(line[:-1].replace('\t', ' ').replace('<', '&lt;').replace('>', '&gt;'))
+ out.append('</td></tr>')
+ out.append('</table>>')
+
+ return QuotedString(''.join(out))
+
+
+if len(sys.argv) != 4:
+ print >>sys.stderr, "Usage: %s FILE.ddx FUNCTION OUT-FILE" % (sys.argv[0],)
+ print >>sys.stderr
+ print >>sys.stderr, "Output format will be auto-detected from the extension on OUT-FILE."
+ print >>sys.stderr, "FUNCTION may contain the encoded type signature:"
+ print >>sys.stderr, " (e.g. 'doIt(IILjava/lang/String;)')"
+ sys.exit(1)
+
+(ddx, func, out) = sys.argv[1:]
+
+lines = []
+
+infile = open(ddx, 'r')
+
+for line in infile:
+ m = re.search(r'^\.method [a-z ]+ ([a-zA-Z0-9_<>]+\(.*)', line)
+ if m:
+ if m.group(1).startswith(func):
+ break
+
+header = []
+
+for line in infile:
+ if line.startswith(' ') or line.startswith('\t'):
+ lines.append(line)
+ break
+ else:
+ header.append(line)
+
+for line in infile:
+ if line.startswith('.end method'):
+ break
+ lines.append(line)
+
+gensym_cnt = 0
+def gensym():
+ global gensym_cnt
+ gensym_cnt += 1
+ return "tmp_" + str(gensym_cnt)
+
+def findExit(lines):
+ this_label = None
+ candidate = False
+ return_blocks = set()
+
+ for line in lines:
+ m = re.search(r'^(\w+):', line)
+ if m:
+ if candidate:
+ return_blocks.add(this_label)
+ this_label = m.group(1)
+ candidate = False
+
+ if line.strip().startswith('return'):
+ candidate = True
+ else:
+ candidate = False
+ return return_blocks
+
+
+exitBlocks = findExit(lines)
+graph = pydot.Dot()
+was_goto = False
+in_switch = False
+
+code = header
+block = 'header'
+
+def switchBlock(to):
+ global block
+ if not was_goto:
+ graph.add_edge(pydot.Edge(block, to))
+ exitBlock()
+ block = to
+
+def exitBlock():
+ node = pydot.Node(block, shape='box', fontname='monospace')
+ node.set_label(as_html(code))
+ graph.add_node(node)
+ del code[:]
+
+def addEdgeTo(to,label='jmp'):
+ if to in exitBlocks:
+ to = gensym()
+ node = pydot.Node(to, label='return')
+ graph.add_node(node)
+
+ graph.add_edge(pydot.Edge(block, to, taillabel=label))
+
+switchBlock('entry')
+
+(NONE, SPARSE, PACKED) = range(3)
+
+for line in lines:
+ code.append(line)
+
+ if in_switch:
+ l = line.strip()
+ if l.startswith('default:'):
+ addEdgeTo(l.split()[-1], 'default')
+ in_switch = False
+ continue
+ else:
+ if in_switch == PACKED:
+ lbl = l.split()[0]
+ case = l.split()[-1]
+ else: # SPARSE
+ lbl = l.split()[-1]
+ case = l.split()[0]
+ addEdgeTo(lbl, case)
+ continue
+
+ m = re.search(r'^(\w+):', line)
+ if m:
+ del code[-1]
+ switchBlock(m.group(1))
+ continue
+ was_goto = False
+
+ insn = line.strip()
+
+ if insn.startswith('if-'):
+ to = insn.split(",")[-1]
+ addEdgeTo(to, 'true')
+ switchBlock(gensym())
+
+ if insn.startswith('return'):
+ addEdgeTo('return', '')
+ was_goto = True
+ if insn.startswith('throw'):
+ was_goto = True
+ elif insn.startswith('packed-switch'):
+ in_switch = PACKED
+ was_goto = True
+ elif insn.startswith('sparse-switch'):
+ in_switch = SPARSE
+ was_goto = True
+ elif insn.startswith('goto'):
+ addEdgeTo(insn.split()[-1], 'goto')
+ was_goto = True
+
+if code:
+ exitBlock()
+
+extn = out[out.rindex(".")+1:]
+graph.write(out, format=extn)

0 comments on commit 92e679a

Please sign in to comment.