Commits

congzheng committed 76caa51

Add modules: call in/out, show smali codes, AndroidManifest.xml,etc

  • Participants
  • Parent commits fce2c83

Comments (0)

Files changed (48)

     def getDex(self):
         return self.apk.get_dex()
     
-    

File APKInfo.pyc

Binary file modified.
+import os
+import sys
+
+from startQT import SYSPATH
+
+class APKtool:
+    
+    # succesFlag == 1: It calls the apktool to decompile the apk to smali codes successfully
+    successFlag = None
+    firstFlag = None
+    lastClassName = None
+    
+    
+    
+    def __init__(self, filename):
+        self.successFlag = 0
+        self.firstFlag = 0
+        self.lastClassName = ""
+        self.callAPKtool(filename)
+        
+    
+    # use the apktool to get the smali codes and AndroidManifest.xml
+    # return 1: success ; return 0: fail
+    def callAPKtool(self, filename):
+        outputPath = SYSPATH + "/temp/ApktoolOutput"
+        cmd = "apktool d -d " + filename + " " + outputPath
+        if os.system(cmd) !=0:
+            self.successFlag = 0
+        else:
+            self.successFlag = 1
+
+
+    def getManifest(self):
+        if self.successFlag == 0:
+            return [0, ""]
+        
+        path = SYSPATH + "/temp/ApktoolOutput/AndroidManifest.xml"
+        try:
+            data = open(path, "r").read()
+        except IOError:
+            print "IOError"
+            data = ""
+        return [1, data]
+
+
+    # get the smali codes
+    def getSmaliCode(self, className):
+        if self.successFlag == 0:
+            return [0, ""]
+        
+        className = className[1:-1] + ".java"
+        # the first time to call method "getSmaliCode"
+        if self.firstFlag == 0:
+            self.firstFlag ==1
+            self.lastClassName = className
+            classPath = SYSPATH + "/temp/ApktoolOutput/smali/" + className
+            try:
+                data = open(classPath, "r").read()
+            except IOError:
+                print "IOError"
+                data = ""
+            return [1, data]
+        
+        # if the lastClassName is equal to className, the smali codes need not to be updated
+        if self.firstFlag == 1:
+            if self.lastClassName == className:
+                return [0, ""] 
+            else:
+                self.lastClassName = className
+                classPath = SYSPATH + "/temp/ApktoolOutput/" + className
+                data = open(classPath, "r").read()
+                return [1, data]

File APKtool.pyc

Binary file added.

File AndroidGui.e4p

 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE Project SYSTEM "Project-4.6.dtd">
 <!-- eric4 project file for project AndroidGui -->
-<!-- Saved: 2011-07-24, 23:46:22 -->
+<!-- Saved: 2011-08-18, 18:21:23 -->
 <!-- Copyright (C) 2011 ,  -->
 <Project version="4.6">
   <Language></Language>
     <Source>Graph.py</Source>
     <Source>xdotParser.py</Source>
     <Source>InputDialog.py</Source>
-    <Source>jad.py</Source>
     <Source>Ui_InputDialog.py</Source>
     <Source>newMessageBox.py</Source>
     <Source>CodeEditor.py</Source>
     <Source>SyntaxHighter.py</Source>
     <Source>SearchFilter.py</Source>
+    <Source>RenamingDialog.py</Source>
+    <Source>Ui_RenamingDialog.py</Source>
+    <Source>Ui_FindDialog.py</Source>
+    <Source>FindDialog.py</Source>
+    <Source>Global.py</Source>
+    <Source>CallInOut.py</Source>
+    <Source>Ui_CallInOutDialog.py</Source>
+    <Source>CallInOutDialog.py</Source>
+    <Source>JAD.py</Source>
+    <Source>APKtool.py</Source>
   </Sources>
   <Forms>
     <Form>MainWindow.ui</Form>
     <Form>InputDialog.ui</Form>
+    <Form>RenamingDialog.ui</Form>
+    <Form>FindDialog.ui</Form>
+    <Form>CallInOutDialog.ui</Form>
   </Forms>
   <Translations>
   </Translations>

File CallInOut.py

+import re
+import copy
+import sys
+
+class CallInOut:
+    # the global dict
+    # idDir:{id ---> method}
+    # idDir2:{method ---> id}
+    # invokeDir:{the invoked method id---> the invoking method id}
+    # invokeDir2:{the invoking method id---> the invoked method id}
+    idDir={}
+    idDir2={}
+    invokeDir={}
+    invokeDir2 = {}
+
+    def __init__(self, methodInvokeList):
+        self.preprocess(methodInvokeList)
+    
+
+    # This function is to pre-process the invoke relations.
+    # I just want to add indexes for querying fastly.
+    def preprocess(self, methodInvokeList):
+        pattern="(.*) ---> (.*)"
+        id=0
+        ID0=0
+        ID1=0
+    
+        for line in methodInvokeList:
+            li=re.search(pattern,line).groups()
+            # if the recursion exists, the detect loop will not be end
+            if li[0] == li[1]:
+                continue		
+        
+            if li[0] not in list(self.idDir.values()):
+                self.idDir[id]=li[0]
+                self.idDir2[li[0]]=id
+                ID0=id
+                id=id+1
+            else:
+                ID0=self.idDir2[li[0]]
+    
+            if li[1] not in list(self.idDir.values()):
+                self.idDir[id]=li[1]
+                self.idDir2[li[1]]=id
+                ID1=id
+                id=id+1
+            else:
+                ID1=self.idDir2[li[1]]
+            
+            if ID1 not in list(self.invokeDir.keys()):
+                self.invokeDir[ID1]=[ID0]
+            else:
+                if ID0 not in self.invokeDir[ID1]:
+                    self.invokeDir[ID1].append(ID0)
+
+            if ID0 not in list(self.invokeDir2.keys()):
+                self.invokeDir2[ID0]=[ID1]
+            else:
+                if ID1 not in self.invokeDir2[ID0]:
+                    self.invokeDir2[ID0].append(ID1)
+    
+    
+    # This function is to search the "call out" methods
+    def searchCallOut(self, method):
+        callOutIdList = []
+        if method in list(self.idDir.values()):
+            if self.idDir2[method] not in self.invokeDir2.keys():
+                return []
+            else:
+                for i in self.invokeDir2[self.idDir2[method]]:
+                    callOutIdList.append(self.idDir[i])
+        
+        return callOutIdList
+                
+                
+                
+    # This function is to search the "call in" methods            
+    def searchCallIn(self, method):
+        callInIdList = []
+        idDirList = list(self.idDir.values())
+        idDir2List = []
+        for m in idDirList:
+            if m.find("^") == -1:
+                continue
+            m0 = m.split("^")[0]
+            m1 = m.split("^")[1]
+
+            if m0 == method:
+                if self.idDir2[m] not in self.invokeDir.keys():
+                    pass
+                else:
+                    for i in self.invokeDir[self.idDir2[m]]:
+                        callInIdList.append(self.idDir[i] + "^" +m1)
+        return callInIdList
+                
+    
+    
+    
+    
+    

File CallInOut.pyc

Binary file added.

File CallInOutDialog.py

+# -*- coding: utf-8 -*-
+
+"""
+Module implementing CallInOutDialog.
+"""
+
+from PyQt4.QtGui import QDialog
+from PyQt4.QtCore import pyqtSignature
+
+from Ui_CallInOutDialog import Ui_CallInOutDialog
+
+class CallInOutDialog(QDialog, Ui_CallInOutDialog):
+    """
+    Class documentation goes here.
+    """
+    callInFlag = 0
+    callOutFlag = 0
+    callMethod = None
+    
+    def __init__(self, parent = None):
+        """
+        Constructor
+        """
+        QDialog.__init__(self, parent)
+        self.setupUi(self)
+    
+    @pyqtSignature("bool")
+    def on_pushButton_ok_clicked(self, checked):
+        """
+        Slot documentation goes here.
+        """
+        className = str(self.lineEdit_class.text())
+        methodName = str(self.lineEdit_method.text())
+        descriptor = str(self.lineEdit_descriptor.text())
+        self.callInFlag = self.checkBox_in.isChecked()
+        self.callOutFlag = self.checkBox_out.isChecked()
+        self.callMethod = className + " " + descriptor + "," + methodName
+        

File CallInOutDialog.pyc

Binary file added.

File CallInOutDialog.ui

+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CallInOutDialog</class>
+ <widget class="QDialog" name="CallInOutDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>601</width>
+    <height>332</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Call in/out Dialog</string>
+  </property>
+  <widget class="QLabel" name="label">
+   <property name="geometry">
+    <rect>
+     <x>120</x>
+     <y>20</y>
+     <width>351</width>
+     <height>17</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>Please input the method to get the call in/out methods</string>
+   </property>
+  </widget>
+  <widget class="QLabel" name="label_5">
+   <property name="geometry">
+    <rect>
+     <x>20</x>
+     <y>50</y>
+     <width>531</width>
+     <height>17</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>Example:Lcom/dlp/SMSReplicatorSecret/ShadyDB; (Landroid/content/Context;)V,&lt;init&gt;</string>
+   </property>
+  </widget>
+  <widget class="QWidget" name="">
+   <property name="geometry">
+    <rect>
+     <x>20</x>
+     <y>90</y>
+     <width>551</width>
+     <height>29</height>
+    </rect>
+   </property>
+   <layout class="QHBoxLayout" name="horizontalLayout">
+    <item>
+     <widget class="QLabel" name="label_2">
+      <property name="text">
+       <string>Class Name:  </string>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <widget class="QLineEdit" name="lineEdit_class">
+      <property name="text">
+       <string>Lcom/dlp/SMSReplicatorSecret/ShadyDB;</string>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QWidget" name="">
+   <property name="geometry">
+    <rect>
+     <x>20</x>
+     <y>140</y>
+     <width>551</width>
+     <height>29</height>
+    </rect>
+   </property>
+   <layout class="QHBoxLayout" name="horizontalLayout_2">
+    <item>
+     <widget class="QLabel" name="label_3">
+      <property name="text">
+       <string>Method Name:</string>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <widget class="QLineEdit" name="lineEdit_method">
+      <property name="text">
+       <string>&lt;init&gt;</string>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QWidget" name="">
+   <property name="geometry">
+    <rect>
+     <x>20</x>
+     <y>190</y>
+     <width>551</width>
+     <height>29</height>
+    </rect>
+   </property>
+   <layout class="QHBoxLayout" name="horizontalLayout_3">
+    <item>
+     <widget class="QLabel" name="label_4">
+      <property name="text">
+       <string>Descriptor:    </string>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <widget class="QLineEdit" name="lineEdit_descriptor">
+      <property name="text">
+       <string>(Landroid/content/Context;)V</string>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QWidget" name="">
+   <property name="geometry">
+    <rect>
+     <x>200</x>
+     <y>240</y>
+     <width>231</width>
+     <height>24</height>
+    </rect>
+   </property>
+   <layout class="QHBoxLayout" name="horizontalLayout_4">
+    <item>
+     <widget class="QCheckBox" name="checkBox_in">
+      <property name="text">
+       <string>Call in</string>
+      </property>
+      <property name="checked">
+       <bool>true</bool>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <widget class="QCheckBox" name="checkBox_out">
+      <property name="text">
+       <string>Call out</string>
+      </property>
+      <property name="checked">
+       <bool>true</bool>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QWidget" name="">
+   <property name="geometry">
+    <rect>
+     <x>50</x>
+     <y>290</y>
+     <width>461</width>
+     <height>29</height>
+    </rect>
+   </property>
+   <layout class="QHBoxLayout" name="horizontalLayout_5">
+    <item>
+     <widget class="QPushButton" name="pushButton_ok">
+      <property name="maximumSize">
+       <size>
+        <width>85</width>
+        <height>27</height>
+       </size>
+      </property>
+      <property name="text">
+       <string>OK</string>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <widget class="QPushButton" name="pushButton_cancel">
+      <property name="maximumSize">
+       <size>
+        <width>85</width>
+        <height>27</height>
+       </size>
+      </property>
+      <property name="text">
+       <string>Cancel</string>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>pushButton_cancel</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>CallInOutDialog</receiver>
+   <slot>close()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>409</x>
+     <y>302</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>485</x>
+     <y>288</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>pushButton_ok</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>CallInOutDialog</receiver>
+   <slot>close()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>167</x>
+     <y>294</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>78</x>
+     <y>276</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>

File CodeEditor.py

-
 from PyQt4.QtGui import *
 from PyQt4.QtCore import *
 from SyntaxHighter import *
-
+from RenamingDialog import *
+from Ui_MainWindow import Ui_mainWindow
 
 class LineNumberArea(QWidget):
     codeEditor = None
         QWidget.__init__(self, editor)
         self.codeEditor = editor
         
-        
     def sizeHint(self):
         return QSize(self.codeEditor.lineNumberAreaWidth(), 0)
         
 class CodeEditor(QPlainTextEdit):
     lineNumberArea = None
     
+    # allLineNumber is the number of rows of dalvik code editor
+    allLineNumber = None
+    
+    # annotation is the content in annotation editor
+    annotation = None
+    
+    # this is the flag for annotation editor.
+    # flag == 0 : it never open/create the annotaion editor
+    # flag == 1 : the annotation editor has been created.  
+    #             After the user click the "Add Annotation" item firstly, the annotation editor is created
+    flag = None
+    
+    annotationDockWidget = None
+    
+    # firstOpenFlag == 1: the annotation editor has been opened once.
+    firstOpenFlag = None
+    
+    # this a flag for each opened method.
+    # flag == 0: there is no annotation for this method
+    # flag == 1: there is a annotation for this method
+    methodOpened2AnnotationFlag = None
+    
+    # this the annotation content for each opened method
+    method2annotation = None
+    
+    # this is the current method which is being opened and viewed.
+    currentMethod = None
+    
+    renamingDockWidget = None
+    
+    # this is a flag for each opened method
+    # flag == 0: there is no reanaming table for this method
+    # flag == 1: there is a renaming table for this method
+    methodOpened2RenamingFlag = None
+    
+    # this is the renaming table for each opened method 
+    method2renaming = None
+    
+    # this is the new codes after renaming
+    method2NewCodes = None
+    
+    # renamingTable is the content in renaming table
+    renamingTable = None
+    
+    # this is the flag for the renaming table.
+    # flag == 0 : it never open/create the renaming table
+    # flag == 1 : the renaming table has been created.  
+    #             After the user click the "Renaming" item firstly, the renaming table is created
+    flagRenaming = None   
+   
+    # firstRenameFlag == 1: the renaming table editor has been opened once.
+    firstRenameFlag = None
+    
     def __init__(self, parent = None):
         QPlainTextEdit.__init__(self, parent)
+        self.allLineNumber = 0
+        self.annotation = ""
+        self.flag = 0
+        self.firstOpenFlag = 0
+        self.methodOpened2AnnotationFlag = {}
+        self.method2annotation = {}
+        
+        self.renamingTable = {}
+        self.methodOpened2RenamingFlag = {}
+        self.method2renaming = {}
+        self.method2NewCodes = {}
+        self.flagRenaming = 0
+        self.firstRenameFlag = 0
+        
         self.lineNumberArea = LineNumberArea(self)
         self.connect(self, SIGNAL("blockCountChanged(int )"), self.updateLineNumberAreaWidth)
         self.connect(self, SIGNAL("updateRequest(QRect, int)"), self.updateLineNumberArea)
         self.connect(self, SIGNAL("cursorPositionChanged()"), self.highlightCurrentLine)
         
-        self.updateLineNumberAreaWidth(0)
+        self.updateLineNumberAreaWidth()
         self.highlightCurrentLine()
         
         highlighter = Highlighter(self.document())
-        
-        
+
+    
+
+
+    
+    # get the line number area's width
     def lineNumberAreaWidth(self):
         digits = 1
         max = self.blockCount()
         
         space = 3+ QFontMetrics(QFont('Latin', 20)).width("9") * digits
         return space
-        
-    def updateLineNumberAreaWidth(self, newBlockCount):
+    
+    # update the line number area's width
+    def updateLineNumberAreaWidth(self):
         self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0)
         
+    # update the line number area
     def updateLineNumberArea(self, rect, dy):
         if dy:
             self.lineNumberArea.scroll(0, dy)
             self.lineNumberArea.update(0, rect.y(), self.lineNumberArea.width(), rect.height())
         
         if rect.contains(self.viewport().rect()):
-            self.updateLineNumberAreaWidth(0)
+            self.updateLineNumberAreaWidth()
             
             
     def resizeEvent(self, e):
             top = bottom
             bottom = top + self.blockBoundingRect(block).height()
             blockNumber = blockNumber + 1
+            
 
 
+    # this contextMenuEvent method is to build a mouse menu
+    def contextMenuEvent(self, event):
+        menu = self.createStandardContextMenu()
+        menu.addSeparator()
+        actionGotoCFG = menu.addAction("Goto CFG")
+        actionAnnotation = menu.addAction("Add Annotation")
+        actionRenaming = menu.addAction("Renaming")
+        self.connect(actionGotoCFG, SIGNAL("triggered()"), self.gotoCFG)
+        self.connect(actionAnnotation, SIGNAL("triggered()"), self.addAnnotation)
+        self.connect(actionRenaming, SIGNAL("triggered()"), self.renaming)
+        menu.exec_(event.globalPos())
+    
+
+
+    # overload the method for calculating the all line numbers
+    def setPlainText(self, plainText):
+        QPlainTextEdit.setPlainText(self, plainText)
+        self.allLineNumber = len(plainText.split("\n")) - 1
+    
+    # reset all
+    def reset(self):
+        if self.flag == 1:
+            self.annotationDockWidget.setVisible(0)
+            self.annotationDockWidget = None
+        self.allLineNumber = 0
+        self.annotation = ""
+        self.flag = 0
+        self.firstOpenFlag = 0
+        self.methodOpened2AnnotationFlag.clear()
+        self.method2annotation.clear()
+        self.currentMethod = None
+    
+        if self.flagRenaming == 1:
+            self.renamingDockWidget.setVisible(0)
+            self.renamingDockWidget = None
+        self.renamingTable.clear()
+        self.methodOpened2RenamingFlag.clear()
+        self.method2renaming.clear()
+        self.method2NewCodes.clear()
+        self.flagRenaming = 0
+        self.firstRenameFlag = 0       
+ 
+   
+    # save the annotation
+    def saveAnnotation(self):
+        self.method2annotation[self.currentMethod] = self.annotationDockWidget.widget().toPlainText()
+        
+    # update the annotation in the annotation editor
+    def updateAnnotation(self):
+        self.annotationDockWidget.widget().setPlainText(self.annotation)
+    
+    # add an opened method
+    def addOpenedMethod(self, method):
+        self.currentMethod = method
+        if method in self.methodOpened2AnnotationFlag.keys():
+            return
+        else:
+            # if it creates a method firstly, the flag is set to 0. 
+            # That is to say, there's no annotation for the method when it's create at the first time.
+            self.methodOpened2AnnotationFlag[self.currentMethod] = 0
+
+            # if it creates a method firstly, the flag is set to 0. 
+            # That is to say, there's no renaming table for the method when it's create at the first time.
+            self.methodOpened2RenamingFlag[self.currentMethod] = 0
+            
+            # set the inital annotation for this method to be used next time.
+            content = ""
+            for i in range(0, self.allLineNumber):
+                content += "\n"
+            self.method2annotation[method] = content
+            self.annotation = content
+        
+            # set the inital renaming table for this method to be used next time
+            self.renamingTable = {}
+            for i in range(0, self.allLineNumber):
+                for j in range(0, 20):
+                    self.renamingTable[20*i + j] = QString("")
+            self.method2renaming[method] = self.renamingTable
+            
+            
+
+
+    # goto the CFG when the user click the GotoCFG
+    def gotoCFG(self):
+        currentCursor = self.textCursor()
+        currentCursor.select(QTextCursor.LineUnderCursor)
+        text = currentCursor.selectedText()
+        lineContent = str(text)
+        if text.startsWith(QString("0x")) == 0:
+            return
+        lineOffset = lineContent[2:lineContent.index(" ")]
+
+        # change the string type to hex type
+        offset = int(lineOffset, 16)
+        
+        import Global
+        graph = Global.GRAPH
+        tabWidget = Global.TABWIDGET
+        for node in graph.nodeList:
+            if node.minOffset <= offset and node.maxOffset >= offset:
+                tabWidget.setCurrentIndex(0)
+                node.setSelected(1)
+                graph.view.centerOn(node)
+                break
+        
+        
+    # open the Annotation view, which is implemented by a QDockWidget
+    def addAnnotation(self):
+        import Global
+        mainwindow = Global.MAINWINDOW
+        
+        # set the flag to 1 for the openning method.
+        # the flag ==1 means that the current method has a annotation.
+        if self.currentMethod == None:
+            return
+        if self.methodOpened2AnnotationFlag[self.currentMethod] == 0:
+            self.methodOpened2AnnotationFlag[self.currentMethod] = 1
+            
+        # get the current line number of the cursor
+        cursorLineNumber = self.textCursor().blockNumber()
+         
+        # there's no annotation editor now and it will create the editor. 
+        if self.flag == 0:
+            index2title = {1:"Annotation--Dalvik", 2:"Annotation--Java", 3:"Annotation--Bytecode"}
+            index2layout = {1:mainwindow.gridLayout_12, 2:mainwindow.gridLayout_13, 3:mainwindow.gridLayout_14}
+            index2widget = {1:mainwindow.plainTextEdit_dalvik, 2:mainwindow.plainTextEdit_java, 3:mainwindow.plainTextEdit_bytecode}
+            
+            index = mainwindow.tabWidget.currentIndex()
+            
+            title = index2title[index]
+            layout = index2layout[index]
+            widget = index2widget[index]        
+            
+            plainTextEdit  = CodeEditor()
+            sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+            sizePolicy.setHorizontalStretch(0)
+            sizePolicy.setVerticalStretch(0)
+            sizePolicy.setHeightForWidth(plainTextEdit.sizePolicy().hasHeightForWidth())
+            plainTextEdit.setSizePolicy(sizePolicy)
+            plainTextEdit.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
+            plainTextEdit.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
+            plainTextEdit.setLineWrapMode(QPlainTextEdit.NoWrap)
+            plainTextEdit.setCenterOnScroll(False)
+            plainTextEdit.setMinimumHeight(100)
+            plainTextEdit.setMaximumHeight(100)
+            
+            self.annotationDockWidget = QDockWidget(title)
+            self.annotationDockWidget.setFeatures(QDockWidget.DockWidgetClosable)
+            self.annotationDockWidget.setWidget(plainTextEdit)
+            self.annotationDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas)
+            self.annotationDockWidget.setVisible(1)
+            self.annotationDockWidget.setFloating(1)
+            mainwindow.addDockWidget(Qt.BottomDockWidgetArea, self.annotationDockWidget)
+            layout.addWidget(self.annotationDockWidget, 1, 0, 1, 1)
+
+            # update a annotation
+            self.updateAnnotation()
+            
+            # set the curosr
+            for i in range(0, cursorLineNumber):
+                self.annotationDockWidget.widget().moveCursor(QTextCursor.Down, QTextCursor.MoveAnchor)
+            
+            # set the annotation editor's flag to 1 
+            self.flag = 1
+            
+            # It means the annotation editor has been opened once
+            self.firstOpenFlag = 1
+            
+        elif self.flag == 1:
+            if self.firstOpenFlag == 1:
+                self.annotationDockWidget.setVisible(1)
+            elif self.firstOpenFlag == 0:
+                self.annotationDockWidget.setVisible(1)
+                self.annotation = self.method2annotation[self.currentMethod]
+                self.updateAnnotation()
+                self.firstOpenFlag = 1
+            self.annotationDockWidget.widget().moveCursor(QTextCursor.Start, QTextCursor.MoveAnchor)
+            # set the curosr
+            for i in range(0, cursorLineNumber):
+                self.annotationDockWidget.widget().moveCursor(QTextCursor.Down, QTextCursor.MoveAnchor)
+
+
+
+    # update the renaming table
+    def updateRenamingTable(self):
+        for i in range(0, self.allLineNumber):
+            for j in range(0, 20):
+                text = self.renamingTable[20*i + j]
+                self.renamingDockWidget.widget().setItem(i, j, QTableWidgetItem(text))
+        
+    # save the renaming table
+    def saveRenamingTable(self):
+        renamingTable = {}
+        for i in range(0, self.allLineNumber):
+            for j in range(0, 20):
+                if self.renamingDockWidget.widget().item(i, j) != None:
+                    renamingTable[20*i + j] = self.renamingDockWidget.widget().item(i, j).text()
+                else:
+                    renamingTable[20*i + j] = QString("")
+        
+        self.method2renaming[self.currentMethod] = renamingTable
+
+    # save the new codes.
+    def saveNewCodes(self):
+        self.method2NewCodes[self.currentMethod] = self.toPlainText()
+
+    # when the user select rigister's name or other name, he can rename it
+    def renaming(self):
+        import Global
+        mainwindow = Global.MAINWINDOW
+        
+        # set the flag to 1 for the openning method.
+        # the flag ==1 means that the current method has a renaming table.
+        if self.currentMethod == None:
+            return
+        if self.methodOpened2RenamingFlag[self.currentMethod] == 0:
+            self.methodOpened2RenamingFlag[self.currentMethod] = 1
+        
+        cursor = self.textCursor()
+        # get the current line number of the cursor
+        cursorLineNumber = cursor.blockNumber()
+         
+        # there's no renaming table now and it will create the renaming table. 
+        if self.flagRenaming == 0:
+            index2title = {1:"RenamingTable--Dalvik", 2:"RenamingTable--Java", 3:"RenamingTable--Bytecode"}
+            index2layout = {1:mainwindow.gridLayout_12, 2:mainwindow.gridLayout_13, 3:mainwindow.gridLayout_14}
+            
+            index = mainwindow.tabWidget.currentIndex()
+            
+            title = index2title[index]
+            layout = index2layout[index]
+            
+            # at most, a line has 10 elements to be renamed
+            renamingTable = QTableWidget(self.allLineNumber, 20)
+            headerLabels = ["A0", "A1"," B0", "B1", "C0", "C1", "D0", "D1", "E0", "E1", "F0", "F1", "G0", "G1", "H0", "H1", "I0", "I1", "J0", "J1"]
+            renamingTable.setHorizontalHeaderLabels(headerLabels)
+            
+          
+            sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+            sizePolicy.setHorizontalStretch(0)
+            sizePolicy.setVerticalStretch(0)
+            sizePolicy.setHeightForWidth(renamingTable.sizePolicy().hasHeightForWidth())
+            renamingTable.setSizePolicy(sizePolicy)
+            renamingTable.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
+            renamingTable.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
+            renamingTable.setMinimumHeight(100)
+            renamingTable.setMaximumHeight(100)
+            
+            self.renamingDockWidget = QDockWidget(title)
+            self.renamingDockWidget.setFeatures(QDockWidget.DockWidgetClosable)
+            self.renamingDockWidget.setWidget(renamingTable)
+            self.renamingDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas)
+            self.renamingDockWidget.setVisible(1)
+            self.renamingDockWidget.setFloating(1)
+            mainwindow.addDockWidget(Qt.BottomDockWidgetArea, self.renamingDockWidget)
+            layout.addWidget(self.renamingDockWidget, 1, 0, 1, 1)
+            
+            # update the renaming table
+            self.updateRenamingTable()
+    
+            # set the curosr in renaming table
+            self.renamingDockWidget.widget().setCurrentItem(self.renamingDockWidget.widget().item(cursorLineNumber, 0))
+            
+            # set the renaming table's flag to 1 
+            self.flagRenaming = 1
+            
+            # firstRenameFlag ==1 means the renaming table has been opened once
+            self.firstRenameFlag = 1
+            
+        elif self.flagRenaming == 1:
+            if self.firstRenameFlag == 1:
+                self.renamingDockWidget.setVisible(1)
+            elif self.firstRenameFlag == 0:
+                self.renamingDockWidget.setVisible(1)
+                self.renamingTable = self.method2renaming[self.currentMethod]
+                self.updateRenamingTable()
+                self.firstRenameFlag = 1
+            # set the curosr in renaming table
+            self.renamingDockWidget.widget().setCurrentItem(self.renamingDockWidget.widget().item(cursorLineNumber, 0))
+
+        
+        
+        # pop a dialog to rename the selected string
+        selectedText = cursor.selectedText()
+        if len(selectedText.split(" ")) != 1 or selectedText == QString(""):
+            return
+        else:
+            renamingDialog = RenamingDialog()
+            renamingDialog.lineEdit_old.setText(selectedText)
+            renamingDialog.exec_()
+            newText = renamingDialog.newName
+            if newText == None or newText == QString(""):
+                return
+            
+            # update the renaming table by add two item at blank space
+            for i in range(0, 20, 2):
+                itemText = self.renamingDockWidget.widget().item(cursorLineNumber, i).text()
+                if itemText == QString("") or itemText == selectedText:
+                    self.renamingDockWidget.widget().item(cursorLineNumber, i).setText(selectedText)
+                    self.renamingDockWidget.widget().item(cursorLineNumber, i+1).setText(newText)
+                    break
+            
+            # change the string to a new string
+            cursor.insertText(newText)
+            
+            # update the node in CFG
+            cursor.select(QTextCursor.LineUnderCursor)
+            text = cursor.selectedText()
+            lineContent = str(text)
+            if text.startsWith(QString("0x")) == 0:
+                return
+            lineOffset = lineContent[2:lineContent.index(" ")]
+
+            # change the string type to hex type
+            offset = int(lineOffset, 16)
+        
+            import Global
+            graph = Global.GRAPH
+            tabWidget = Global.TABWIDGET
+            for node in graph.nodeList:
+                if node.minOffset <= offset and node.maxOffset >= offset:
+                    break
+            
+            tList =  node.text().split("\n")
+            firstLine = tList[0]
+            endLine = tList[-2]
+            for row in tList:
+                rowOffset = row[:row.index(" ")]
+                # change the string type to hex type
+                rowOffset = int(rowOffset, 16)
+                if rowOffset == offset:
+                    break
+            updatedText = node.text().replace(row, text)
+            node.setText(updatedText)
+
+    
+    

File CodeEditor.pyc

Binary file modified.

File FindDialog.py

+# -*- coding: utf-8 -*-
+
+"""
+Module implementing FindDialog.
+"""
+from PyQt4.QtGui import *
+from PyQt4.QtCore import *
+from PyQt4.QtGui import QDialog
+from PyQt4.QtCore import pyqtSignature
+
+from Ui_FindDialog import Ui_FindDialog
+
+class FindDialog(QDialog, Ui_FindDialog):
+    """
+    Class documentation goes here.
+    """
+    findHistroyList = None
+    
+    options = None
+    
+    widget = None
+    
+    def __init__(self, parent = None):
+        """
+        Constructor
+        """
+        QDialog.__init__(self, parent)
+        self.setupUi(self)
+        
+        self.comboBox.setEditable(1)
+        self.findHistroyList = QStringList()
+
+    @pyqtSignature("bool")
+    def on_pushButton_find_clicked(self, checked):
+        """
+        Slot documentation goes here.
+        """
+        lineEditText = self.comboBox.lineEdit().text()
+        if lineEditText == QString(""):
+            return
+        else:
+            if self.comboBox.findText(lineEditText) == -1:
+                self.comboBox.insertItem(0,lineEditText)
+                self.findHistroyList.append(lineEditText)
+            else:
+                self.comboBox.removeItem(self.comboBox.findText(lineEditText))
+                self.comboBox.insertItem(0, lineEditText)
+                self.comboBox.setEditText(lineEditText)
+
+        self.options = QTextDocument.FindFlags(0)
+        
+        # CaseSensitivity
+        if self.checkBox_1.isChecked():
+            self.options = self.options.__ior__(QTextDocument.FindCaseSensitively)
+
+        # Backward
+        if self.checkBox_3.isChecked():
+            self.options = self.options.__ior__(QTextDocument.FindBackward)
+            
+        # WholeWords
+        if self.checkBox_2.isChecked():
+            self.options = self.options.__ior__(QTextDocument.FindWholeWords)
+
+        self.widget.find(lineEditText, self.options)
+        
+        
+    def setWidget(self, widget):
+        self.widget = widget
+        self.moveCursorToStart()
+        
+    def moveCursorToStart(self):
+        cursor = self.widget.textCursor()
+        selectedText = cursor.selectedText()
+        cursor.movePosition(QTextCursor.Start, QTextCursor.MoveAnchor)
+    
+    def setFindHistroyList(self, findHistroyList):
+        self.findHistroyList = findHistroyList
+        self.comboBox.insertItems(0, self.findHistroyList)
+    
+

File FindDialog.pyc

Binary file added.

File FindDialog.ui

+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>FindDialog</class>
+ <widget class="QDialog" name="FindDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Find</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>false</bool>
+  </property>
+  <property name="modal">
+   <bool>false</bool>
+  </property>
+  <widget class="QLabel" name="label">
+   <property name="geometry">
+    <rect>
+     <x>30</x>
+     <y>30</y>
+     <width>64</width>
+     <height>17</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>Search for</string>
+   </property>
+  </widget>
+  <widget class="QCheckBox" name="checkBox_1">
+   <property name="geometry">
+    <rect>
+     <x>30</x>
+     <y>100</y>
+     <width>94</width>
+     <height>22</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>Match case</string>
+   </property>
+  </widget>
+  <widget class="QCheckBox" name="checkBox_2">
+   <property name="geometry">
+    <rect>
+     <x>30</x>
+     <y>130</y>
+     <width>169</width>
+     <height>22</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>Match entire word only</string>
+   </property>
+  </widget>
+  <widget class="QCheckBox" name="checkBox_3">
+   <property name="geometry">
+    <rect>
+     <x>30</x>
+     <y>160</y>
+     <width>134</width>
+     <height>22</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>Search backwards</string>
+   </property>
+   <property name="checked">
+    <bool>false</bool>
+   </property>
+  </widget>
+  <widget class="QCheckBox" name="checkBox_4">
+   <property name="geometry">
+    <rect>
+     <x>30</x>
+     <y>190</y>
+     <width>106</width>
+     <height>22</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>Wrap around</string>
+   </property>
+   <property name="checked">
+    <bool>true</bool>
+   </property>
+   <property name="tristate">
+    <bool>false</bool>
+   </property>
+  </widget>
+  <widget class="QComboBox" name="comboBox">
+   <property name="geometry">
+    <rect>
+     <x>30</x>
+     <y>50</y>
+     <width>341</width>
+     <height>31</height>
+    </rect>
+   </property>
+   <property name="editable">
+    <bool>true</bool>
+   </property>
+  </widget>
+  <widget class="QPushButton" name="pushButton_close">
+   <property name="geometry">
+    <rect>
+     <x>230</x>
+     <y>240</y>
+     <width>85</width>
+     <height>27</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>Close</string>
+   </property>
+  </widget>
+  <widget class="QPushButton" name="pushButton_find">
+   <property name="geometry">
+    <rect>
+     <x>80</x>
+     <y>240</y>
+     <width>85</width>
+     <height>27</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>Find</string>
+   </property>
+  </widget>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>pushButton_close</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>FindDialog</receiver>
+   <slot>close()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>303</x>
+     <y>257</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>352</x>
+     <y>256</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>

File GetMethods.py

 import androguard, analysis, androlyze
 import bytecode
 
+from dvm import *
 
-from dvm import *
+
 
 class CLASS:
     apk = None
     vm = None
+    vmx = None
     def __init__(self, apk):
         self.apk = apk
         self.vm = DalvikVMFormat(apk.getDex())
                 maxdepth = l
                 
         return maxdepth
+
+
+    #get where a permission is used
+    def get_permission(self):
+        pathDict = {}
+        self.vmx = analysis.VMAnalysis(self.vm)
+        perms_access = self.vmx.tainted_packages.get_permissions([])
+        for perm in perms_access:
+            pathDict[perm] = self.show_path(perms_access[perm])
         
+        return pathDict
+  
+    
+    def show_path(self, paths):
+        accessPathList = []
+        for path in paths:
+            if isinstance(path,analysis.PathP):
+                if path.get_access_flag() == analysis.TAINTED_PACKAGE_CALL:
+                    accessPath = ("%s %s %s (@%s-0x%x)  --->  %s %s %s") % (path.get_method().get_class_name(), path.get_method().get_name(), \
+                                                                     path.get_method().get_descriptor(), path.get_bb().get_name(), path.get_bb().start + path.get_idx(), \
+                                                                     path.get_class_name(), path.get_name(), path.get_descriptor())
+                    
+                    accessPathList.append(accessPath)
+            
+        return accessPathList
         
-   
+        
+
+    
+    # All Invoke Methods
+    def get_methodInvoke(self):
+        methodInvokeList = []
+        allMethods = self.vm.get_methods()
+        for m in allMethods:
+            invokingMethod = m.get_class_name() + " " + m.get_descriptor() +"," + m.get_name()
+            code =  m.get_code()
+            if code == None:
+                continue
+            else:
+                bc = code.get_bc()
+                idx = 0
+                lineNum = 1
+                for i in bc.get():
+                    line = i.show_buff(idx)
+                    if line.find("invoke-") >= 0:
+                        index = line.index("[meth@")
+                        method = str(line[index:])
+                        method2 = method.split(" ")                        
+
+                        # set the class
+                        ClassStartIndex = index + len(method2[0]) + len(method2[1]) + 2
+                        className = line[ClassStartIndex : ClassStartIndex + len(method2[2])]
+                        
+                        # set the return type
+                        ReturnStartIndex = index + method.rindex(")") + 2
+                        returnType = line[ReturnStartIndex : ReturnStartIndex+len(method2[-2])]
+                        
+                        # set the method name 
+                        NameStartIndex = index + method.rindex(" ") + 1
+                        methodName = line[NameStartIndex : NameStartIndex + len(method2[-1]) - 1]
+                        
+                        # set the parameter name
+                        ParameterStartIndex = index + method.index("(")
+                        ParameterEndIndex = index + method.rindex(")") + 1
+                        parameterName = line[ParameterStartIndex : ParameterEndIndex]
+                        
+                        # set the descriptor name
+                        descriptorName = parameterName +returnType
+                        
+                        invokedMethod = className + " " +descriptorName+ "," + methodName
+                        methodInvokeList.append(invokingMethod +" ---> " + invokedMethod + "^Line:"+str(lineNum)+"  Offset:"+"0x%x" % idx)
+                        
+                    lineNum += 1
+                    idx += i.get_length() 
+                        
+        return methodInvokeList

File GetMethods.pyc

Binary file modified.
+global TABWIDGET
+global DALVIKEDIT
+global GRAPH
+global MAINWINDOW

File Global.pyc

Binary file added.
 
 
 from  InputDialog import *
-from Ui_InputDialog import Ui_inputDialog_smali
+from Ui_InputDialog import Ui_inputDialog_dalvik
 
 
 
     scene = None
     view = None
     pageSize = [100, 100]
+    root = None
+    nodeList = []
     
     def __init__(self):
         super(GraphicsView, self).__init__()
 
         # set the drag mode
         self.setDragMode(QGraphicsView.ScrollHandDrag)
-        
-        
+    
     def wheelEvent(self, event):
         factor = 1.41 ** (event.delta()/240.0)
         self.scale(factor, factor)
         self.pageSize[0] = pagesize[0]
         self.pageSize[1] = pagesize[1]
     
-    
-    
-    def initShow(self, tab_cfg,  gridLayout):
+
+    def initShow(self, tab_cfg,  gridLayout, tabWidget, dalvikEdit):
         self.view = GraphicsView()
         self.scene = QGraphicsScene()
         self.scene.setSceneRect(0, 0, self.pageSize[0], self.pageSize[1])
         self.view.setScene(self.scene)
         gridLayout.addWidget(self.view)
+        import Global 
+        Global.TABWIDGET = tabWidget
+        Global.DALVIKEDIT = dalvikEdit
 
     
-    def show(self, nodeList, linkList):
-                
+    def show(self, nodeList, linkList):    
         self.scene.clear()
-        self.scene.setSceneRect(0, 0, self.pageSize[0], self.pageSize[1])
+        self.scene.setSceneRect(0, 0, self.pageSize[0]*2, self.pageSize[1]*2)
+        del self.nodeList[:]
+        import copy
+        self.nodeList = copy.copy(nodeList)
+        
+        #for node in nodeList:
+        #    self.scene.addItem(node)
+        #for link in linkList:
+        #    self.scene.addItem(link)
+        #self.root = QGraphicsItemGroup(None, self.scene)
+        
+        # I just want to crate a root QGraphicsItem object, which is None. So it creates a Link object for convenience.
+        # Qt has a bug in translate function. I crate a root item to implement translate function.
+        self.root = Link()
         
         for node in nodeList:
-            self.scene.addItem(node)
+            node.setParentItem(self.root)
+        for link in linkList:
+            link.setParentItem(self.root)
+        self.scene.addItem(self.root)
         
-        for link in linkList:
-            self.scene.addItem(link)
-        
+        self.root.translate(0, 0)
 
 
 class Link(QGraphicsLineItem):
-    myFromNode = None
-    myToNode = None
     painterPath = None
     color = None
     
-    def __init__(self, fromNode = None, toNode = None):
+    def __init__(self):
         QGraphicsLineItem.__init__(self)        
-        self.myFromNode = fromNode
-        self.myToNode = toNode
         self.painterPath = QPainterPath()
         self.myColor = Qt.black
         self.setFlags(QGraphicsLineItem.ItemIsMovable | QGraphicsLineItem.ItemIsSelectable)
     width = 0.0
     height = 0.0
     font = None
+    hint = None
+    minOffset = 0
+    maxOffset = 0
     
     
     def __init__(self, aleft = 0.0, atop = 0.0, awidth = 0.0, aheight = 0.0):
         self.myOutlineColor = QColor(Qt.darkGray)
         self.myBackgroundColor = QColor(Qt.white)
 #        self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable)
-        self.setFlags(QGraphicsItem.ItemIsSelectable)
+        self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable)
         self.left = aleft
         self.top = atop
         self.width = awidth
         self.height = aheight
-        
         self.font = QFont("Courier", 5, -1, 0)
-
+        self.setAcceptHoverEvents(1)
 
     
     def setText(self, text):
         self.prepareGeometryChange()
-        self.myText = text
+        self.myText = str(text)
         self.update()
+        # after getting the text, it can get the min and max offset
+        self.getMinMaxOffset()
+    
+    def getMinMaxOffset(self):
+        text =  self.myText.split("\n")
+        firstLine = text[0]
+        endLine = text[-2]
+        self.minOffset = firstLine[:firstLine.index(" ")]
+        self.maxOffset = endLine[:endLine.index(" ")]
+        # change the string type to hex type
+        self.minOffset = int(self.minOffset, 16)
+        self.maxOffset = int(self.maxOffset, 16)
     
     def text(self):
-        return text
+        return self.myText
     
     def setTextColor(self, color):
         self.myTextColor = color
 #        if ok and not text.isEmpty():
 #            self.setText(text)
 
-        inputDialog_smali = inputDialog(self, self.myText)
-        inputDialog_smali.exec_()
+        inputDialog_dalvik = inputDialog(self, self.myText)
+        inputDialog_dalvik.exec_()
 
+    def hoverEnterEvent(self, event):
+        pos = event.pos()
+        self.hint = Hint(pos.x(), pos.y(), self.width, self.height, self.myText)
+        scene = self.scene()
+        scene.addItem(self.hint)
+    
+    def hoverLeaveEvent(self, event):
+        scene = self.scene()
+        scene.removeItem(self.hint)
+    
+    def keyPressEvent(self, event):
+        # If the user press the space key, the view will change to Dalvik from CFG.
+        if event.key() == Qt.Key_Space:
+            startLineNumber = "0x" + self.myText[:self.myText.index(" ")]
+            lineNumber = len(self.myText.split("\n")) - 1
+            import Global
+            Global.TABWIDGET.setCurrentIndex(1)
+            # set the cursor's background color 
+            colorFormat = QTextCharFormat()
+            colorFormat.setBackground(QColor(Qt.gray).lighter(145))
+            document = Global.DALVIKEDIT.document()
+            cursor = document.find(startLineNumber + " ")
+            for i in range(0, lineNumber - 1):
+                cursor.movePosition(QTextCursor.Down, QTextCursor.KeepAnchor)
+            cursor.movePosition(QTextCursor.EndOfLine, QTextCursor.KeepAnchor)
+            cursor.mergeCharFormat(colorFormat)
+            Global.DALVIKEDIT.setTextCursor(cursor)
+            Global.DALVIKEDIT.ensureCursorVisible()
 
 
+class Hint(QGraphicsItem):
+    text = None
+    left = 0.0
+    top = 0.0
+    width = 0.0
+    height = 0.0
     
-  
+    def __init__(self, aleft = 0.0, atop = 0.0, awidth = 0.0, aheight = 0.0, text = None):
+        QGraphicsItem.__init__(self)
+        self.text = text
+        self.left = aleft
+        self.top = atop
+        self.width = awidth
+        self.height = aheight
+    
+    def outlineRect(self):
+        rect = QRectF(self.left, self.top, self.width, self.height)
+        return rect 
+ 
+    def boundingRect(self):
+        Margin = 1
+        return self.outlineRect().adjusted(-Margin, -Margin, +Margin, +Margin)  
 
+    def paint(self, painter, option, widget = None):
+        pen = QPen(Qt.white)
+        if option.state & QStyle.State_Selected:
+            pen.setStyle(Qt.DotLine)
+            pen.setWidth(2)
+        painter.setPen(pen)
+        brushColor = QColor(Qt.gray).lighter(140)
+        painter.setBrush(brushColor)
+        rect = self.outlineRect()
+        painter.drawRect(rect)
+        painter.setPen(Qt.blue)
+        painter.setFont(QFont("Courier", 5, -1, 0))
+        painter.drawText(rect, Qt.AlignLeft | Qt.AlignVCenter, self.text)    
     
-    

File Graph.pyc

Binary file modified.

File InputDialog.py

 from PyQt4.QtGui import QDialog
 from PyQt4.QtCore import pyqtSignature
 
-from Ui_InputDialog import Ui_inputDialog_smali
+from Ui_InputDialog import Ui_inputDialog_dalvik
 
-class inputDialog(QDialog, Ui_inputDialog_smali):
+class inputDialog(QDialog, Ui_inputDialog_dalvik):
     """
     Class documentation goes here.
     """
         """
         QDialog.__init__(self)
         self.setupUi(self)
-        self.plainTextEdit_smali.setPlainText(myText)
+        self.plainTextEdit_dalvik.setPlainText(myText)
         self.node = node
 
     
     @pyqtSignature("")
-    def on_pushButton_ok_smali_clicked(self):
+    def on_pushButton_ok_dalvik_clicked(self):
         """
         Slot documentation goes here.
         """
 
-        newText = self.plainTextEdit_smali.toPlainText()
+        newText = self.plainTextEdit_dalvik.toPlainText()
         self.node.setText(newText)
         
         

File InputDialog.pyc

Binary file modified.

File InputDialog.ui

 <?xml version="1.0" encoding="UTF-8"?>
 <ui version="4.0">
- <class>inputDialog_smali</class>
- <widget class="QDialog" name="inputDialog_smali">
+ <class>inputDialog_dalvik</class>
+ <widget class="QDialog" name="inputDialog_dalvik">
   <property name="geometry">
    <rect>
     <x>0</x>
    <item row="0" column="0">
     <layout class="QGridLayout" name="gridLayout">
      <item row="0" column="0">
-      <widget class="QPlainTextEdit" name="plainTextEdit_smali">
+      <widget class="QPlainTextEdit" name="plainTextEdit_dalvik">
        <property name="lineWrapMode">
         <enum>QPlainTextEdit::NoWrap</enum>
        </property>
       </widget>
      </item>
      <item row="1" column="0">
-      <layout class="QHBoxLayout" name="horizontalLayout_smali">
+      <layout class="QHBoxLayout" name="horizontalLayout_dalvik">
        <item>
-        <widget class="QPushButton" name="pushButton_ok_smali">
+        <widget class="QPushButton" name="pushButton_ok_dalvik">
          <property name="sizePolicy">
           <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
            <horstretch>0</horstretch>
         </widget>
        </item>
        <item>
-        <widget class="QPushButton" name="pushButton_cancel_smali">
+        <widget class="QPushButton" name="pushButton_cancel_dalvik">
          <property name="sizePolicy">
           <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
            <horstretch>0</horstretch>
  <resources/>
  <connections>
   <connection>
-   <sender>pushButton_ok_smali</sender>
+   <sender>pushButton_ok_dalvik</sender>
    <signal>clicked()</signal>
-   <receiver>inputDialog_smali</receiver>
+   <receiver>inputDialog_dalvik</receiver>
    <slot>close()</slot>
    <hints>
     <hint type="sourcelabel">
    </hints>
   </connection>
   <connection>
-   <sender>pushButton_cancel_smali</sender>
+   <sender>pushButton_cancel_dalvik</sender>
    <signal>clicked()</signal>
-   <receiver>inputDialog_smali</receiver>
+   <receiver>inputDialog_dalvik</receiver>
    <slot>close()</slot>
    <hints>
     <hint type="sourcelabel">
+import os
+import sys
+import zipfile
+
+from startQT import SYSPATH
+
+# delete all files and dirs in the "./temp/" dictionary
+# return 0: success;
+def clear():
+    cmd = "rm -rf " + SYSPATH + "/temp/*"
+    return os.system(cmd)
+
+
+
+# use the dex2jar to generate the .jar file.
+# Then move .jar file to the "./temp/" dictionary
+# At last, unzip the .jar file to "./temp/" dictionary
+# return 1: success ; return 0: fail
+def dex2jar(filename):
+    cmd1 = SYSPATH +"/dex2jar/dex2jar.sh " + filename
+    if os.system(cmd1) !=0:
+        return 0
+    
+    newfilename = os.path.split(filename)[-1] + ".dex2jar.jar"
+    cmd2 = "mv " + os.path.dirname(filename) + "/" + newfilename + " " + SYSPATH + "/temp/"
+    if os.system(cmd2) !=0:
+        return 0
+        
+    if unzip(SYSPATH + "/temp/" + newfilename) != 0:
+        return 0
+    
+    return 1
+    
+
+
+# unzip the .jar file
+# return 0: success;
+def unzip(filename):
+    cmd = "unzip -o " + filename + " -d" + SYSPATH + "/temp/unzip"
+    return os.system(cmd)
+
+
+
+# decompile the apk to the Javacodes
+# parameter:
+#       filename: the full absolute path of the apk file
+# return 1: success; return 0:fail
+def decompile(filename):
+    if clear() != 0:
+        return 0
+        
+    if dex2jar(filename) != 1:
+        return 0
+    
+    cmd = SYSPATH + "/jad158e.linux.static/jad -o -r -sjava -d" + SYSPATH + "/temp/java " + SYSPATH + "/temp/unzip/**/*.class"
+    if os.system(cmd) != 0:
+        return 0
+ 
+    return 1
+
+
+
+    
+    
+    

File JAD.pyc

Binary file added.

File MainWindow.ui

         <item row="0" column="0">
          <widget class="QTabWidget" name="tabWidget">
           <property name="currentIndex">
-           <number>3</number>
+           <number>5</number>
           </property>
           <property name="documentMode">
            <bool>false</bool>
            </attribute>
            <layout class="QGridLayout" name="gridLayout_11"/>
           </widget>
-          <widget class="QWidget" name="tab_smali">
+          <widget class="QWidget" name="tab_dalvik">
            <property name="sizePolicy">
             <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
              <horstretch>0</horstretch>
             </sizepolicy>
            </property>
            <attribute name="title">
-            <string>Smali</string>
+            <string>Dalvik</string>
            </attribute>
            <layout class="QGridLayout" name="gridLayout_12"/>
           </widget>
            </attribute>
            <layout class="QGridLayout" name="gridLayout_14"/>
           </widget>
+          <widget class="QWidget" name="tab_smali">
+           <attribute name="title">
+            <string>Smali</string>
+           </attribute>
+           <layout class="QGridLayout" name="gridLayout_15"/>
+          </widget>
+          <widget class="QWidget" name="tab_callinout">
+           <attribute name="title">
+            <string>Call in/out</string>
+           </attribute>
+           <layout class="QGridLayout" name="gridLayout_16">
+            <item row="0" column="0">
+             <widget class="QTextEdit" name="textEdit_call"/>
+            </item>
+           </layout>
+          </widget>
+          <widget class="QWidget" name="tab_permission">
+           <attribute name="title">
+            <string>Permission</string>
+           </attribute>
+           <layout class="QGridLayout" name="gridLayout_17">
+            <item row="0" column="0">
+             <widget class="QTextEdit" name="textEdit_permission"/>
+            </item>
+           </layout>
+          </widget>
+          <widget class="QWidget" name="tab_manifest">
+           <attribute name="title">
+            <string>AndroidManifest.xml</string>
+           </attribute>
+           <layout class="QGridLayout" name="gridLayout_18">
+            <item row="0" column="0">
+             <widget class="QTextBrowser" name="textBrowser"/>
+            </item>
+           </layout>
+          </widget>
          </widget>
         </item>
        </layout>
       </widget>
       <widget class="QWidget" name="win2">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
        <property name="minimumSize">
         <size>
-         <width>279</width>
+         <width>298</width>
          <height>524</height>
         </size>
        </property>
              </size>
             </property>
             <property name="currentIndex">
-             <number>1</number>
+             <number>3</number>
             </property>
             <widget class="QWidget" name="tab_file">
              <attribute name="title">
      <string>Tools(&amp;T)</string>
     </property>
     <addaction name="actFind"/>
+    <addaction name="actCall_in_out"/>
    </widget>
    <widget class="QMenu" name="menuHelp_H">
     <property name="title">
    <property name="text">
     <string>New(&amp;N)</string>
    </property>
+   <property name="shortcut">
+    <string>Ctrl+N</string>
+   </property>
   </action>
   <action name="actOpen">
    <property name="icon">
    <property name="text">
     <string>Find(&amp;F)</string>
    </property>
+   <property name="shortcut">
+    <string>Ctrl+F</string>
+   </property>
   </action>
   <action name="About">
    <property name="text">
     <string>About</string>
    </property>
   </action>
+  <action name="actCall_in_out">
+   <property name="text">
+    <string>Call in/out</string>
+   </property>
+  </action>
  </widget>
  <resources>
   <include location="src/images/mainwindow.qrc"/>
 6. Run this tool:
 
 	python startQT.py
+
+
+[Others]: if you miss python lib dependency, you should install with the following two steps:
+	(1) sudo apt-get install ipython
+	(2) sudo apt-get install python-scipy  

File RenamingDialog.py

+# -*- coding: utf-8 -*-
+
+"""
+Module implementing RenamingDialog.
+"""
+
+from PyQt4.QtGui import QDialog
+from PyQt4.QtCore import pyqtSignature
+
+from Ui_RenamingDialog import Ui_RenamingDialog
+
+class RenamingDialog(QDialog, Ui_RenamingDialog):
+    """
+    Class documentation goes here.
+    """
+    newName = None
+    def __init__(self, parent = None):
+        """
+        Constructor
+        """
+        QDialog.__init__(self, parent)
+        self.setupUi(self)
+    
+    @pyqtSignature("bool")
+    def on_pushButton_ok_clicked(self, checked):
+        """
+        Slot documentation goes here.
+        """
+        self.newName = self.lineEdit_new.text()

File RenamingDialog.pyc

Binary file added.

File RenamingDialog.ui

+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>RenamingDialog</class>
+ <widget class="QDialog" name="RenamingDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>351</width>
+    <height>254</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <widget class="QWidget" name="gridLayoutWidget">
+   <property name="geometry">
+    <rect>
+     <x>30</x>
+     <y>30</y>
+     <width>291</width>
+     <height>131</height>
+    </rect>
+   </property>
+   <layout class="QGridLayout" name="gridLayout">
+    <item row="3" column="0">
+     <widget class="QLineEdit" name="lineEdit_new"/>
+    </item>
+    <item row="1" column="0">
+     <widget class="QLineEdit" name="lineEdit_old">
+      <property name="enabled">
+       <bool>false</bool>
+      </property>
+     </widget>
+    </item>
+    <item row="0" column="0">
+     <widget class="QLabel" name="label">
+      <property name="text">
+       <string>Rename</string>
+      </property>
+     </widget>
+    </item>
+    <item row="2" column="0">
+     <widget class="QLabel" name="label_2">
+      <property name="text">
+       <string>To</string>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QPushButton" name="pushButton_ok">
+   <property name="geometry">
+    <rect>
+     <x>50</x>
+     <y>190</y>
+     <width>85</width>
+     <height>27</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>Ok</string>
+   </property>
+  </widget>
+  <widget class="QPushButton" name="pushButton_cancel">
+   <property name="geometry">
+    <rect>
+     <x>180</x>
+     <y>190</y>
+     <width>85</width>
+     <height>27</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>Cancel</string>
+   </property>
+  </widget>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>pushButton_cancel</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>RenamingDialog</receiver>
+   <slot>close()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>259</x>
+     <y>205</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>292</x>
+     <y>206</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>pushButton_ok</sender>
+   <signal>clicked(bool)</signal>
+   <receiver>RenamingDialog</receiver>
+   <slot>close()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>65</x>
+     <y>211</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>209</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>

File SearchInvoke.pyc

Binary file added.

File SyntaxHighter.py

         # deine the type pattern
         self.typePattern = QRegExp("\\[type@.*\\]")    
     
-    
+        # define the field format
+        fieldFormatLabel = QTextCharFormat()
+        fieldFormatClass = QTextCharFormat()
+        fieldFormatType = QTextCharFormat()
+        fieldFormatName = QTextCharFormat()
+        
+        # set the field format
+        fieldFormatLabel.setForeground(QColor(255, 0, 51))
+        fieldFormatLabel.setFontWeight(QFont.Bold)
+        fieldFormatClass.setForeground(QColor(255, 204, 0))
+        fieldFormatClass.setFontWeight(QFont.Bold)
+        fieldFormatType.setForeground(QColor(77, 100, 23))
+        fieldFormatType.setFontWeight(QFont.Bold)
+        fieldFormatName.setForeground(QColor(102, 51, 102))
+        fieldFormatName.setFontWeight(QFont.Bold)
+        self.fieldFormat = [fieldFormatLabel, fieldFormatClass, fieldFormatType, fieldFormatName]
+        
+        # deine the field pattern
+        self.fieldPattern = QRegExp("\\[field@.*\\]")   
+        
         # define the number pattern
         numberPattern = QRegExp("\\b[0-9]+\\b")
         self.highlightingRules.append([numberPattern, self.numberFormat])
             self.highlightingRules.append([QRegExp(pattern), self.keywordFormat2])            
 
             
-
-
-        
-
-        
-        
-        
-            
-    def highlightBlock(self, text):
-        
-        
+    def highlightBlock(self, text): 
         # highlight the keywords , numbers .etc in the highlightingRules
         for rule in self.highlightingRules:
             expression = QRegExp(rule[0])
             ValueStartIndex = LabelEndIndex + 1
             VauleEndIndex = index + type.rindex("]")
             self.setFormat(ValueStartIndex, VauleEndIndex - ValueStartIndex, self.typeFormat[1])
+        
+            index = expression.indexIn(text, index + length)            
+ 
+ 
+        # highlight the field
+        expression = QRegExp(self.fieldPattern)
+        index = expression.indexIn(text)        
+        while index >= 0:
+            length = expression.matchedLength()
+            field = str(text[index:index+length])
+            field2 = field.split(" ")
+            
+            # set the label format
+            LabelStartIndex = index + 1
+            LabelEndIndex = index + len(field2[0]) + len(field2[1]) + 1
+            self.setFormat(LabelStartIndex, LabelEndIndex - LabelStartIndex, self.fieldFormat[0])
+            
+            # set the field class format
+            ValueStartIndex = LabelEndIndex + 1
+            ValueEndIndex = ValueStartIndex + len(field2[2])
+            self.setFormat(ValueStartIndex, ValueEndIndex - ValueStartIndex, self.fieldFormat[1])
+            
+            # set the field type format
+            TypeStartIndex = ValueEndIndex + 1
+            TypeEndIndex = TypeStartIndex + len(field2[3])
+            self.setFormat(TypeStartIndex, TypeEndIndex - TypeStartIndex, self.f