首页 > 代码库 > 跟着鬼哥学PyQtPart.4

跟着鬼哥学PyQtPart.4

中秋假期转眼已经过去两天了,我们的学习也在不断向前,经过前面三篇文章的学习,我们已经可以做出来一个简单的反编译apk的工具了。

为了更方便的使用我们自己编写的工具,所以我们对于第三篇文章中的search_file button来进行处理,我们使用拖拽文件到QLineEdit控件上面来显示文件路径,而不用打开window来选择了,这样对我们的操作来说更加方便一点。

 

0x1:拖拽事件的处理

拖拽事件,经过一晚上的查询以及翻看Java已经写好的工具,终于找到dragEnterEventdropEvent两个事件。关于这两个事件的详细介绍,自行google搜索一下即可。

要想使用这个事件,我们需要重写一下QLineEdit控件,并且在其init方法里面设置setAcceptDropsTrue来接收拖拽事件。

所以现在的问题就是我们如何来获取得到拖入文件的路径呢?

经过查询mimeData有一些方法可以参考,经过测试,urls()属性还是比较贴近我们所需的,但是还需要对其进行处理得到文件路径。

详细代码如下:


def dropEvent(self, event):

        ###获取拖放过来的文件的路径

        st=str(event.mimeData().urls())

        print(st)

        ###这里没发现好的api,所以用mimeData()的urls属性了,text()不好用,所以下面就是字符串截取,来还原路径

        a='///'

        b=')]'

        
        num2=st.index(b)-1

        num=st.index(a)+3

        st=st[num:num2]

        ##这里定义全局变量,拖入文件或者文件夹的路径

        global APK_STR

        APK_STR=st
            
        self.setText(st)



0x2:重新做一下布局文件

详细代码如下,有详细注释,这里不再多说:


 QWidget.__init__(self, parent)
        self.setWindowTitle('Android_APK')
        ###第一行
        self.apk_decode=QPushButton("Apk_Decode")
        self.apk_path_edit = MyEditText(self)
        
        ###第二行,三个按钮,这里第三个按钮的点击事件还没写
        self.apk_build=QPushButton("Apk_Build")
        self.apk_build_edit = MyEditText()

        ###第三行
        self.sign = QPushButton("Apk_Sign")
        self.apk_sign_edit = MyEditText()

        ##第四行
        self.shootcut=QPushButton("Shoot_Cut")
        self.shootcut_text=QLabel("please keep moile with usb")
        

        ###布局文件的编写,四行两列
        grid = QGridLayout()
        grid.setSpacing(10)

        grid.addWidget(self.apk_decode, 1, 0)
        grid.addWidget(self.apk_path_edit, 1, 1)
        
        grid.addWidget(self.apk_build, 2, 0)
        grid.addWidget(self.apk_build_edit, 2, 1)

        grid.addWidget(self.sign,3,0)
        grid.addWidget(self.apk_sign_edit, 3,1)

        grid.addWidget(self.shootcut,4,0)
        grid.addWidget(self.shootcut_text, 4,1)

        
        ###设置窗口的高宽,将gridview放入大布局中
        self.setLayout(grid)
        self.resize(450, 300)


效果图如下:





0x3:整合相关按钮的点击事件

 

前面一篇文章已经将反编译的按钮事件做好,所以这里我们照着写一下回编译和签名以及最后的截屏事件即可。



def apkD(self):

        ###上面openFIle方法中定义的全局变量,打印一下路径,看看是否正确#####
        print(APK_STR)

        ###apktool的命令使用#####
        apkToD='java -jar apktool.jar d '+APK_STR

        ###调用os的system命令来执行cmd的相关命令###
        os.system(apkToD)

    def apkB(self):

        ###上面openFIle方法中定义的全局变量,打印一下路径,看看是否正确#####
        print(APK_STR)

        ###apktool的命令使用#####
        apkToD='java -jar apktool.jar b '+APK_STR

        ###调用os的system命令来执行cmd的相关命令###
        os.system(apkToD)

    def apkS(self):

        apkSign='java -jar signapk.jar testkey.x509.pem testkey.pk8 '+APK_STR+' Signed_apk.apk'

        print apkSign

        ###调用os的system命令来执行cmd的相关命令###
        os.system(apkSign)


    def shootCut(self):

        pre_com='adb wait-for-device'
        os.system(pre_com)

        ###将截图保存到local下
        fir_com='adb shell screencap -p /data/local/tmp/tmp.png'

        print (fir_com)

        os.system(fir_com)
        
        ###当前时间,精确到秒,来保存图片命名
        timestamp = time.strftime('%Y-%m-%d-%H-%M-%S',time.localtime(time.time()))

        path=os.getcwd()

        ###将其导出来
        sec_com='adb pull /data/local/tmp/tmp.png '+path+'\\'+timestamp+'.png'

        print(sec_com)
        os.system(sec_com)

        thi_com='adb shell rm /data/local/tmp/tmp.png'

        os.system(thi_com)



0x4:完整的代码

下面附上完整的代码,有兴趣的朋友,直接测试即可。记得先配置好pyqt相关开发环境。


# -*- coding: utf-8 -*-
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
import os
import time


class MainLayout(QWidget):
    
    def __init__(self, parent=None):
        
        QWidget.__init__(self, parent)
        self.setWindowTitle('Android_APK')
        ###第一行
        self.apk_decode=QPushButton("Apk_Decode")
        self.apk_path_edit = MyEditText(self)
        
        ###第二行,三个按钮,这里第三个按钮的点击事件还没写
        self.apk_build=QPushButton("Apk_Build")
        self.apk_build_edit = MyEditText()

        ###第三行
        self.sign = QPushButton("Apk_Sign")
        self.apk_sign_edit = MyEditText()

        ##第四行
        self.shootcut=QPushButton("Shoot_Cut")
        self.shootcut_text=QLabel("please keep moile with usb")

        ###反编译按钮的点击事件
        self.connect(self.apk_decode,SIGNAL('clicked()'),self.apkD)

        ###回编译按钮的点击事件
        self.connect(self.apk_build,SIGNAL('clicked()'),self.apkB)

        ###签名按钮的点击事件
        self.connect(self.sign,SIGNAL('clicked()'),self.apkS)

        ###截屏按钮的点击事件
        self.connect(self.shootcut,SIGNAL('clicked()'),self.shootCut)
        

        ###布局文件的编写,四行两列
        grid = QGridLayout()
        grid.setSpacing(10)

        grid.addWidget(self.apk_decode, 1, 0)
        grid.addWidget(self.apk_path_edit, 1, 1)
        
        grid.addWidget(self.apk_build, 2, 0)
        grid.addWidget(self.apk_build_edit, 2, 1)

        grid.addWidget(self.sign,3,0)
        grid.addWidget(self.apk_sign_edit, 3,1)

        grid.addWidget(self.shootcut,4,0)
        grid.addWidget(self.shootcut_text, 4,1)

        
        ###设置窗口的高宽,将gridview放入大布局中
        self.setLayout(grid)
        self.resize(450, 300)

         
    ''''def openFile(self):
        ##调用QfileDialog的相关方法来打开文件选择框
        s=QFileDialog.getOpenFileName(self,"Open file dialog","/","Apk files(*.apk)")
        ##定义全局变量,用于接收需要反编译的apk的路径
        global APK_STR
        APK_STR=str(s)
        self.apk_path_edit.setText(APK_STR)'''

    def apkD(self):

        ###上面openFIle方法中定义的全局变量,打印一下路径,看看是否正确#####
        print(APK_STR)

        ###apktool的命令使用#####
        apkToD='java -jar apktool.jar d '+APK_STR

        ###调用os的system命令来执行cmd的相关命令###
        os.system(apkToD)

    def apkB(self):

        ###上面openFIle方法中定义的全局变量,打印一下路径,看看是否正确#####
        print(APK_STR)

        ###apktool的命令使用#####
        apkToD='java -jar apktool.jar b '+APK_STR

        ###调用os的system命令来执行cmd的相关命令###
        os.system(apkToD)

    def apkS(self):

        apkSign='java -jar signapk.jar testkey.x509.pem testkey.pk8 '+APK_STR+' Signed_apk.apk'

        print apkSign

        ###调用os的system命令来执行cmd的相关命令###
        os.system(apkSign)


    def shootCut(self):

        pre_com='adb wait-for-device'
        os.system(pre_com)

        ###将截图保存到local下
        fir_com='adb shell screencap -p /data/local/tmp/tmp.png'

        print (fir_com)

        os.system(fir_com)
        
        ###当前时间,精确到秒,来保存图片命名
        timestamp = time.strftime('%Y-%m-%d-%H-%M-%S',time.localtime(time.time()))

        path=os.getcwd()

        ###将其导出来
        sec_com='adb pull /data/local/tmp/tmp.png '+path+'\\'+timestamp+'.png'

        print(sec_com)
        os.system(sec_com)

        thi_com='adb shell rm /data/local/tmp/tmp.png'

        os.system(thi_com)
        
class MyEditText(QLineEdit):
    
    def __init__(self,parent=None):
        
        super(MyEditText,self).__init__(parent)

        #这里在init初始化,接受拖入事件
        self.setAcceptDrops(True)

        
    ###重写两个拖入文件的操作方法
    def dragEnterEvent(self,event):

        event.accept()


    def dropEvent(self, event):

        ###获取拖放过来的文件的路径

        st=str(event.mimeData().urls())

        print(st)

        ###这里没发现好的api,所以用mimeData()的urls属性了,text()不好用,所以下面就是字符串截取,来还原路径

        a='///'

        b=')]'

        
        num2=st.index(b)-1

        num=st.index(a)+3

        st=st[num:num2]

        ##这里定义全局变量,拖入文件或者文件夹的路径

        global APK_STR

        APK_STR=st
            
        self.setText(st)


###程序的主入口
if __name__ == "__main__":       
    app = QApplication(sys.argv)
    qb = MainLayout()
    qb.show()
    sys.exit(app.exec_())




效果图,前面几篇基本都有了,这里不再贴出了。

注意:

1.反编译采用的是apktool.jar的命令,所以得将其放到.py文件对应目录

2.签名采用google的公钥来过的,所以其文件也必须在同目录下

3.截屏动作,得保证手机正常连接usbadb进程不被占用,所以如果读者有自己编译的adb是最好的,若此功能不好用,直接做个cmd脚本将上述方法中的命令放入即可

4.这四篇文章,仅记录一下PyQt的相关学习过程,读者可以随意对其进行扩展开发,做一个IDE工具集合搜索,修改,保存以及一些自动化工具

结束语:

虽然中秋几天假期没有出去玩,不过从头开始学习PyQt还是有一些进步的。代码方面编写肯定是有很多疏漏,其对应功能方面也可以做更多优化,有兴趣的朋友,请继续加油。

仅以一句话勉励自己:

勤能补拙是良训,一分辛苦一分才。

 

相关附件之类的,我就上传到百度网盘了:


 http://pan.baidu.com/s/1o6sONoQ


跟着鬼哥学PyQtPart.4