PDF权限密码解密

[复制链接]
103 |14
发表于 3 天前 | 显示全部楼层 |阅读模式
PDF权限密码解密

用途

批量或单个对权限加密的PDF进行解密,同时可以去除签名。
权限加密指的是禁止编辑、禁止打印等,无法对打开文件需要密码的情况解密。符合上述情况可无需密码直接解密
下载

制作了安装包,添加了右键菜单启动
v1.1 https://flt.lanzouo.com/idU6e30aav6
v1.0: https://flt.lanzouo.com/iGZvA309qcyf
用法

如您希望使用单文件,请下载v1.0,基本没有区别
报毒说明:经反馈,360报毒,好像是因为nuitka打包导致,具体见查毒报告
您可以review 代码,并使用nuitka/pyinstaller和inno setup自行打包使用,或使用同类软件。
    选中PDF文件后右键点击移除权限
    或者在文件夹空白处右键点击移除PDF权限或者右键文件夹移除PDF权限或者将文件(多个文件也可以)或文件夹拖到v1.0.exe上即可,将在文件同一目录下生成_decrypt.pdf​文件。

效果图



说明

因为代码简略,通过复制文件实现,因此文件较大时速度缓慢。
开源地址:https://git.flt6.top/flt/tools/src/branch/master/pdf_unlock
(由于github账号问题,更新不了存储库,暂时使用自建git服务器,如有违规烦请告知)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

发表于 3 天前 | 显示全部楼层
烦请所有遇到闪退的坛友,先认真阅读帖子内容,确实使用方法正确后,带版本号回帖。
回复

使用道具 举报

发表于 3 天前 | 显示全部楼层
我记得有两款软件分别是PDF Shaper和Advanced PDF Password Recovery可以破解加密且可以正常查看的PDF文件的。
回复

使用道具 举报

发表于 3 天前 | 显示全部楼层
PDF中维护了一个表,记录权限、权限密码、所有者密码。如果设置所有者密码,文件内容就被对等加密了,所以不可能解密。而如果只设置权限密码,那直接删除权限密码并将权限设为全部允许就可以了。
这种权限密码是靠软件自觉遵守ISO规范实现的。
回复

使用道具 举报

发表于 3 天前 | 显示全部楼层

实测 能够去掉了密码和签名。

增加2个bat文件实现程序右键菜单调用!


①用来添加右键菜单的bat,名称随意,我这里是【00_Add右键.bat
[Asm]  
  1. @Echo Off
  2. rem HJ合集A名称设置,可修改
  3. set "HJ=Max小工具"
  4. set "np=PDF移除密码签名"
  5. set "p=%cd%\%np%.bat"
  6. Reg.exe add "HKEY_CLASSES_ROOT\*\shell\%HJ%" /f /v "SubCommands" /t REG_SZ /d ""
  7. Reg.exe add "HKEY_CLASSES_ROOT\*\shell\%HJ%" /f /v "Icon" /t REG_SZ /d "imageres.dll,-5310"
  8. Reg.exe add "HKEY_CLASSES_ROOT\*\shell\%HJ%" /v "Position" /t REG_SZ /d "Top" /f
  9. Reg.exe add "HKEY_CLASSES_ROOT\*\shell\%HJ%\shell\%np%\command" /ve /t REG_SZ /d "cmd /c ""%p%" "%%V""" /f
  10. Reg.exe add "HKCR\Directory\shell\%HJ%" /f /v "SubCommands" /t REG_SZ /d ""
  11. Reg.exe add "HKCR\Directory\shell\%HJ%" /f /v "Icon" /t REG_SZ /d "imageres.dll,-5310"
  12. Reg.exe add "HKCR\Directory\shell\%HJ%" /v "Position" /t REG_SZ /d "Top" /f
  13. Reg.exe add "HKCR\Directory\shell\%HJ%\shell\%np%\command" /ve /t REG_SZ /d "cmd /c ""%p%" "%%V""" /f
复制代码




② 【PDF移除密码签名.bat】名称不要改,否则要改上面代码第7行set "np=PDF移除密码签名"
[Asm]  
  1. @echo off
  2. "%~dp0PDF权限密码解密v1.0.exe" "%~nx1"
复制代码



我这里程序名称由【v1.0.exe】改为【PDF权限密码解密v1.0.exe】


功能:文件夹上右键,可调用;PDF文件右键可调用
弄不明白的,可以下载成品 ↓↓↓

链接:https://pan.quark.cn/s/d5b84a3b3249
回复

使用道具 举报

发表于 3 天前 | 显示全部楼层
你这里逻辑不对
```
HKEY_CLASSES_ROOT\*\shell\
```
是向所有文件右键菜单加选项,应该只向pdf后缀加。

```
HKEY_CLASSES_ROOT\SystemFileAssociations\.pdf\shell
```
或者
```
HKEY_CLASSES_ROOT\.pdf\shell
```

还是推荐用我发的1.1版本安装包,避免卸载残留:lol
回复

使用道具 举报

发表于 3 天前 | 显示全部楼层
增加个图形界面的代码:
[Python]  
  1. import tkinter as tk
  2. from tkinter import ttk, filedialog, messagebox
  3. import PyPDF2
  4. from pathlib import Path
  5. import threading
  6. class PDFUnlockerGUI:
  7.     def __init__(self, root):
  8.         self.root = root
  9.         self.root.title("PDF解锁工具")
  10.         self.root.geometry("600x400")
  11.         self.root.resizable(True, True)
  12.         
  13.         # 创建界面
  14.         self.create_widgets()
  15.         
  16.         # 处理状态
  17.         self.is_processing = False
  18.         
  19.     def create_widgets(self):
  20.         """
  21.         创建界面组件
  22.         """
  23.         # 主框架
  24.         main_frame = ttk.Frame(self.root, padding="10")
  25.         main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
  26.         
  27.         # 配置网格权重
  28.         self.root.columnconfigure(0, weight=1)
  29.         self.root.rowconfigure(0, weight=1)
  30.         main_frame.columnconfigure(1, weight=1)
  31.         
  32.         # 输入文件/目录选择
  33.         ttk.Label(main_frame, text="选择文件或目录:").grid(row=0, column=0, sticky=tk.W, pady=5)
  34.         
  35.         self.path_var = tk.StringVar()
  36.         self.path_entry = ttk.Entry(main_frame, textvariable=self.path_var)
  37.         self.path_entry.grid(row=0, column=1, sticky=(tk.W, tk.E), padx=(5, 5), pady=5)
  38.         
  39.         self.browse_button = ttk.Button(main_frame, text="浏览...", command=self.browse_path)
  40.         self.browse_button.grid(row=0, column=2, padx=(5, 0), pady=5)
  41.         
  42.         # 进度条
  43.         self.progress_var = tk.DoubleVar()
  44.         self.progress_bar = ttk.Progressbar(main_frame, variable=self.progress_var, maximum=100)
  45.         self.progress_bar.grid(row=1, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=10)
  46.         
  47.         # 状态标签
  48.         self.status_var = tk.StringVar(value="就绪")
  49.         self.status_label = ttk.Label(main_frame, textvariable=self.status_var)
  50.         self.status_label.grid(row=2, column=0, columnspan=3, sticky=tk.W, pady=5)
  51.         
  52.         # 结果文本框
  53.         self.result_text = tk.Text(main_frame, height=15, width=70)
  54.         self.result_text.grid(row=3, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S), pady=10)
  55.         
  56.         # 滚动条
  57.         scrollbar = ttk.Scrollbar(main_frame, orient=tk.VERTICAL, command=self.result_text.yview)
  58.         scrollbar.grid(row=3, column=3, sticky=(tk.N, tk.S))
  59.         self.result_text.configure(yscrollcommand=scrollbar.set)
  60.         
  61.         # 开始按钮
  62.         self.start_button = ttk.Button(main_frame, text="开始处理", command=self.start_processing)
  63.         self.start_button.grid(row=4, column=1, pady=10)
  64.         
  65.         # 配置结果文本框的网格权重
  66.         main_frame.rowconfigure(3, weight=1)
  67.         
  68.     def browse_path(self):
  69.         """
  70.         浏览文件或目录
  71.         """
  72.         # 创建一个选择对话框
  73.         file_path = filedialog.askopenfilename(
  74.             title="选择PDF文件",
  75.             filetypes=[("PDF files", "*.pdf"), ("All files", "*.*")]
  76.         )
  77.         
  78.         if not file_path:
  79.             # 如果没有选择文件,则尝试选择目录
  80.             dir_path = filedialog.askdirectory(title="选择包含PDF文件的目录")
  81.             if dir_path:
  82.                 self.path_var.set(dir_path)
  83.         else:
  84.             self.path_var.set(file_path)
  85.             
  86.     def copy_pdf_pages(self, input_path: str, output_path: str) -> bool:
  87.         """
  88.         移除PDF文件的所有限制
  89.         
  90.         Args:
  91.             input_path: 输入PDF文件路径
  92.             output_path: 输出PDF文件路径
  93.             
  94.         Returns:
  95.             是否成功移除限制
  96.         """
  97.         try:
  98.             with open(input_path, 'rb') as input_file:
  99.                 reader = PyPDF2.PdfReader(input_file)
  100.                
  101.                 writer = PyPDF2.PdfWriter()
  102.                
  103.                 # 复制所有页面
  104.                 for page in reader.pages:
  105.                     writer.add_page(page)
  106.                
  107.                 # 写入新文件(不设置任何加密或限制)
  108.                 with open(output_path, 'wb') as output_file:
  109.                     writer.write(output_file)
  110.                
  111.                 return True
  112.                
  113.         except Exception as e:
  114.             self.result_text.insert(tk.END, f"处理文件 '{input_path}' 时发生错误: {e}\n")
  115.             return False
  116.    
  117.     def process_files(self):
  118.         """
  119.         在后台线程中处理文件
  120.         """
  121.         input_path = self.path_var.get().strip()
  122.         
  123.         if not input_path:
  124.             messagebox.showerror("错误", "请选择要处理的文件或目录")
  125.             self.is_processing = False
  126.             return
  127.             
  128.         path_obj = Path(input_path)
  129.         
  130.         if not path_obj.exists():
  131.             messagebox.showerror("错误", "指定的文件或目录不存在")
  132.             self.is_processing = False
  133.             return
  134.             
  135.         try:
  136.             if path_obj.is_dir():
  137.                 files = list(path_obj.glob("**/*.pdf"))
  138.             else:
  139.                 files = [path_obj]
  140.                
  141.             total = len(files)
  142.             if total == 0:
  143.                 self.result_text.insert(tk.END, "未找到PDF文件\n")
  144.                 self.status_var.set("未找到PDF文件")
  145.                 self.is_processing = False
  146.                 return
  147.                
  148.             self.result_text.insert(tk.END, f"找到 {total} 个PDF文件\n")
  149.             self.result_text.insert(tk.END, "=" * 50 + "\n")
  150.             
  151.             success_count = 0
  152.             for i, pdf_file in enumerate(files, start=1):
  153.                 if not self.is_processing:  # 用户取消操作
  154.                     break
  155.                     
  156.                 # 更新进度
  157.                 progress = (i / total) * 100
  158.                 self.progress_var.set(progress)
  159.                 self.status_var.set(f"正在处理: {pdf_file.name} ({i}/{total})")
  160.                 self.root.update_idletasks()
  161.                
  162.                 if not pdf_file.is_file():
  163.                     self.result_text.insert(tk.END, f"跳过非PDF文件: {pdf_file}\n")
  164.                     continue
  165.                     
  166.                 output_file = pdf_file.with_name(f"{pdf_file.stem}_decrypt.pdf")
  167.                 success = self.copy_pdf_pages(pdf_file, output_file)
  168.                
  169.                 if success:
  170.                     success_count += 1
  171.                     self.result_text.insert(tk.END, f"✓ {pdf_file.name} 处理成功\n")
  172.                 else:
  173.                     self.result_text.insert(tk.END, f"✗ {pdf_file.name} 处理失败\n")
  174.                     
  175.                 self.result_text.see(tk.END)
  176.                 self.root.update_idletasks()
  177.                
  178.             # 处理完成
  179.             self.progress_var.set(100)
  180.             self.status_var.set(f"处理完成: {success_count}/{total} 个文件成功处理")
  181.             self.result_text.insert(tk.END, "=" * 50 + "\n")
  182.             self.result_text.insert(tk.END, f"处理完成: {success_count}/{total} 个文件成功处理\n")
  183.             
  184.         except Exception as e:
  185.             self.result_text.insert(tk.END, f"处理过程中发生错误: {e}\n")
  186.             self.status_var.set("处理出错")
  187.             
  188.         finally:
  189.             self.is_processing = False
  190.             self.start_button.config(text="开始处理", state=tk.NORMAL)
  191.             
  192.     def start_processing(self):
  193.         """
  194.         开始或停止处理
  195.         """
  196.         if self.is_processing:
  197.             # 停止处理
  198.             self.is_processing = False
  199.             self.start_button.config(text="开始处理", state=tk.NORMAL)
  200.             self.status_var.set("处理已停止")
  201.         else:
  202.             # 开始处理
  203.             self.is_processing = True
  204.             self.start_button.config(text="停止处理", state=tk.NORMAL)
  205.             self.result_text.delete(1.0, tk.END)
  206.             self.progress_var.set(0)
  207.             
  208.             # 在新线程中处理文件,避免阻塞GUI
  209.             thread = threading.Thread(target=self.process_files)
  210.             thread.daemon = True
  211.             thread.start()
  212. def main():
  213.     root = tk.Tk()
  214.     app = PDFUnlockerGUI(root)
  215.     root.mainloop()
  216. if __name__ == "__main__":
  217.     main()
复制代码
回复

使用道具 举报

发表于 3 天前 | 显示全部楼层
非常感谢

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

发表于 3 天前 | 显示全部楼层
还是挺需要这种小工具的。
回复

使用道具 举报

发表于 3 天前 | 显示全部楼层
Win10运行直接闪退!
疑似需要运行环境或者框架
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表