apk解包

查看 81|回复 11
作者:cxr666   
众所周知,吾爱上有一个Gomisic的软件现在只支持windows和安卓系统,所以我准备把这个软件用Xcode编写成ipa上架,但是先得把apk解包才能看到源代码,在吾爱上下了一堆解包工具,不是报毒就是解包不了,所以我用python写了一个很简单的apk解包,原理就是apk是一个压缩文件,只要把后缀改成zip或者rar就可以解包了,为了不麻烦动你们哥哥姐姐的小手手{:1_918:}
以下是核心代码:
设置中文字体支持
    self.font = ("SimHei", 10)
    # APK文件路径
    self.apk_path = tk.StringVar()
    self.create_widgets()
    # 确保D:/apk目录存在
    self.ensure_apk_dir()
def ensure_apk_dir(self):
    """确保D:/apk目录存在"""
    try:
        if not os.path.exists("D:/apk"):
            os.makedirs("D:/apk")
    except Exception as e:
        messagebox.showerror("错误", f"无法创建临时工作目录: {str(e)}")
def create_widgets(self):
    """创建GUI组件"""
    # 标题
    title_label = tk.Label(self.root, text="APK解包工具", font=("SimHei", 16, "bold"))
    title_label.pack(pady=20)
    # APK文件选择区域
    apk_frame = tk.Frame(self.root)
    apk_frame.pack(fill=tk.X, padx=50, pady=10)
    tk.Label(apk_frame, text="APK文件:", font=self.font).pack(side=tk.LEFT, padx=5)
    apk_entry = tk.Entry(apk_frame, textvariable=self.apk_path, width=40, font=self.font)
    apk_entry.pack(side=tk.LEFT, padx=5)
    browse_apk_btn = tk.Button(apk_frame, text="浏览...", command=self.browse_apk, font=self.font)
    browse_apk_btn.pack(side=tk.LEFT, padx=5)
    # 红色提示文字
    red_tip_label = tk.Label(
        self.root,
        text="解包后文件夹默认保存为桌面",
        font=("SimHei", 10, "bold"),
        fg="red"
    )
    red_tip_label.pack(pady=10)
    # 进度条区域
    progress_frame = tk.Frame(self.root)
    progress_frame.pack(fill=tk.X, padx=50, pady=10)
    self.progress_var = tk.DoubleVar()
    self.progress_bar = ttk.Progressbar(
        progress_frame,
        variable=self.progress_var,
        maximum=100,
        length=500
    )
    self.progress_bar.pack(side=tk.LEFT, padx=5)
    self.progress_label = tk.Label(progress_frame, text="0%", font=self.font, width=5)
    self.progress_label.pack(side=tk.LEFT, padx=5)
    # 辅助提示信息
    tip_label = tk.Label(
        self.root,
        text="提示: 解包过程中会使用临时目录,完成后将自动清理",
        font=self.font,
        fg="#666666"
    )
    tip_label.pack(pady=5)
    # 解包按钮
    unpack_btn = tk.Button(
        self.root,
        text="开始解包",
        command=self.unpack_apk,
        font=("SimHei", 12),
        width=15,
        height=2,
        bg="#4CAF50",
        fg="white"
    )
    unpack_btn.pack(pady=20)
    # 状态标签
    self.status_var = tk.StringVar()
    self.status_var.set("就绪")
    status_label = tk.Label(self.root, textvariable=self.status_var, font=self.font, fg="#333333")
    status_label.pack(pady=5)
def browse_apk(self):
    """浏览选择APK文件"""
    file_path = filedialog.askopenfilename(
        title="选择APK文件",
        filetypes=[("APK文件", "*.apk"), ("所有文件", "*.*")]
    )
    if file_path:
        self.apk_path.set(file_path)
def update_progress(self, value):
    """更新进度条,确保不超过100%"""
    progress = min(value, 100)
    self.progress_var.set(progress)
    self.progress_label.config(text=f"{int(progress)}%")
    self.root.update_idletasks()  # 刷新界面
def clean_apk_dir(self):
    """清理D:/apk目录下的所有文件和文件夹"""
    try:
        if os.path.exists("D:/apk"):
            for item in os.listdir("D:/apk"):
                item_path = os.path.join("D:/apk", item)
                try:
                    if os.path.isfile(item_path) or os.path.islink(item_path):
                        os.unlink(item_path)
                    elif os.path.isdir(item_path):
                        shutil.rmtree(item_path)
                except Exception as e:
                    messagebox.showwarning("警告", f"清理临时文件时出错: {str(e)}")
    except Exception as e:
        messagebox.showwarning("警告", f"临时目录清理失败: {str(e)}")
def get_total_files(self, directory):
    """计算目录中文件的总数(不包括目录本身)"""
    total = 0
    for root, dirs, files in os.walk(directory):
        total += len(files)
    return total
def copy_with_progress(self, src, dst, total_files, start_progress, end_progress):
    """带进度的文件复制函数"""
    copied = 0
    progress_range = end_progress - start_progress
    def copy_files(src, dst):
        nonlocal copied
        if os.path.isdir(src):
            # 确保目标目录存在
            if not os.path.exists(dst):
                os.makedirs(dst)
            # 复制目录中的所有项目
            for item in os.listdir(src):
                src_item = os.path.join(src, item)
                dst_item = os.path.join(dst, item)
                copy_files(src_item, dst_item)
        else:
            # 复制文件
            shutil.copy2(src, dst)
            copied += 1
            # 计算进度(确保不会超过设定的结束进度)
            progress = start_progress + (copied / total_files) * progress_range
            self.update_progress(progress)
    copy_files(src, dst)
    # 确保最终进度达到结束进度
    self.update_progress(end_progress)
def unpack_apk(self):
    """解包APK文件的主函数"""
    apk_path = self.apk_path.get()
    # 重置进度条
    self.update_progress(0)
    # 验证输入
    if not apk_path:
        messagebox.showerror("错误", "请选择APK文件")
        return
    if not os.path.exists(apk_path):
        messagebox.showerror("错误", "所选APK文件不存在")
        return
    try:
        # 获取APK文件名(不含扩展名)
        apk_filename = os.path.basename(apk_path)
        apk_name = os.path.splitext(apk_filename)[0]
        # 临时解压目录
        temp_target_path = os.path.join("D:/apk", apk_name)
        # 桌面最终目录
        desktop_path = os.path.join(os.path.expanduser("~"), "Desktop")
        final_target_path = os.path.join(desktop_path, apk_name)
        # 更新状态
        self.status_var.set("正在处理...")
        self.root.update()
        # 创建临时ZIP文件路径
        zip_path = os.path.join("D:/apk", f"{apk_name}.zip")
        # 复制APK文件并重命名为ZIP
        shutil.copy2(apk_path, zip_path)
        self.status_var.set("已转换为压缩文件,正在解压...")
        self.root.update()
        # 解压ZIP文件(带进度)
        with zipfile.ZipFile(zip_path, 'r') as zip_ref:
            # 获取所有文件信息
            file_list = zip_ref.infolist()
            total_files = len(file_list)
            if total_files == 0:
                messagebox.showerror("错误", "APK文件为空或损坏")
                return
            # 确保临时目录存在
            os.makedirs(temp_target_path, exist_ok=True)
            # 逐个解压文件并更新进度(占70%进度)
            for i, file_info in enumerate(file_list, 1):
                zip_ref.extract(file_info, temp_target_path)
                progress = (i / total_files) * 70  # 限制在70%以内
                self.update_progress(progress)
        # 准备复制到桌面
        self.status_var.set("正在复制到桌面...")
        self.root.update()
        # 如果桌面文件夹已存在,先删除
        if os.path.exists(final_target_path):
            shutil.rmtree(final_target_path)
        # 计算总文件数用于进度显示
        total_copy_files = self.get_total_files(temp_target_path)
        if total_copy_files == 0:
            messagebox.showerror("错误", "解压后的文件夹为空")
            return
        # 执行带进度的复制(占30%进度,从70%到100%)
        self.copy_with_progress(temp_target_path, final_target_path, total_copy_files, 70, 100)
        # 清理临时文件和D:/apk目录
        self.status_var.set("正在清理临时文件...")
        self.root.update()
        # 先删除临时ZIP文件
        if os.path.exists(zip_path):
            os.remove(zip_path)
        # 清理D:/apk目录下的所有内容
        self.clean_apk_dir()
        # 进度条完成
        self.update_progress(100)
        # 更新状态并显示成功信息
        self.status_var.set("解包完成")
        messagebox.showinfo(
            "成功",
            f"APK解包成功!\n\n文件已保存到桌面的「{apk_name}」文件夹中。"
        )
    except PermissionError:
        self.status_var.set("解包失败")
        messagebox.showerror("权限错误", "没有足够的权限操作文件,请以管理员身份运行")
    except Exception as e:
        self.status_var.set("解包失败")
        messagebox.showerror("错误", f"解包过程中发生错误: {str(e)}")
成品下载:https://wwcq.lanzouu.com/ieR3Z39dgptg 密码:54g3,感谢支持!
有任何问题评论区反馈谢谢。

文件, 进度

gzsklsskszngc   

这不是真正意义上的解包吧?本身就是个压缩包,7z一样可以解,关键是解出来的数据还是加密的,那就不算是解包。
touristxxp   

先用用,看好用不。
bachelor66   

只是修改后缀后解压缩吗?        
cxr666
OP
  


bachelor66 发表于 2025-10-26 11:25
只是修改后缀后解压缩吗?

对的谢谢
feiyang2024   

谢谢楼主分享,学习一下。
vectai   

顶一下。谢谢楼主老师
yourbestrun   

解包是什么意思?
cxr666
OP
  


yourbestrun 发表于 2025-10-26 10:34
解包是什么意思?

就是将压缩或打包在一起的文件、数据等,还原成原本独立、可直接使用的状态
xyxst   

代码是不是不完整,最前面不对啊
您需要登录后才可以回帖 登录 | 立即注册

返回顶部