├── dedrm_src ├── plugin-import-name-dedrm.txt ├── alfcrypto.dll ├── alfcrypto64.dll ├── alfcrypto_src.zip ├── libalfcrypto.dylib ├── libalfcrypto32.so ├── libalfcrypto64.so ├── pycrypto_des.py ├── encodebase64.py ├── scrolltextwidget.py ├── utilities.py ├── DeDRM_Mobipocket PID_Help.htm ├── DeDRM_EInk Kindle Serial Number_Help.htm ├── argv_utils.py ├── activitybar.py ├── simpleprefs.py ├── openssl_des.py ├── wineutils.py ├── DeDRM_Kindle for Mac and PC Key_Help.htm ├── DeDRM_eReader Key_Help.htm ├── DeDRM_Adobe Digital Editions Key_Help.htm ├── kfxdedrm.py ├── DeDRM_Kindle for Android Key_Help.htm ├── DeDRM_Barnes and Noble Key_Help.htm ├── kindlepid.py ├── subasyncio.py ├── DeDRM_Help.htm ├── zipfix.py ├── askfolder_ed.py ├── scriptinterface.py └── epubtest.py ├── obok_src ├── plugin-import-name-obok_dedrm.txt ├── images │ └── obok.png ├── translations │ ├── ar.mo │ ├── de.mo │ ├── es.mo │ ├── nl.mo │ ├── pt.mo │ ├── de.po │ └── nl.po ├── obok │ ├── __init__.py │ └── legacy_obok.py ├── obok_dedrm_Help.htm ├── __init__.py └── utilities.py ├── contrib ├── DeDRM_Macintosh_Application │ ├── DeDRM.app │ │ └── Contents │ │ │ ├── PkgInfo │ │ │ ├── Resources │ │ │ ├── DeDRM Progress.app │ │ │ │ └── Contents │ │ │ │ │ ├── PkgInfo │ │ │ │ │ ├── MacOS │ │ │ │ │ └── DeDRM Progress │ │ │ │ │ ├── Resources │ │ │ │ │ ├── DeDRM Progress.icns │ │ │ │ │ ├── Scripts │ │ │ │ │ │ └── Window.scpt │ │ │ │ │ └── English.lproj │ │ │ │ │ │ ├── MainMenu.nib │ │ │ │ │ │ └── InfoPlist.strings │ │ │ │ │ └── Info.plist │ │ │ ├── DeDRM.icns │ │ │ ├── description.rtfd │ │ │ │ └── TXT.rtf │ │ │ ├── Scripts │ │ │ │ └── main.scpt │ │ │ └── DeDRM Progress Source.zip │ │ │ ├── MacOS │ │ │ └── droplet │ │ │ └── Info.plist │ ├── DeDRM.app.txt │ └── DeDRM ReadMe.rtf ├── Other_Tools │ ├── Rocket_ebooks │ │ ├── rebhack.zip │ │ └── rebhack_ReadMe.txt │ ├── Scuolabook_DRM │ │ └── Scuolabook_ReadMe.txt │ ├── Tetrachroma_FileOpen_ineptpdf │ │ └── ineptpdf_8.4.51_ReadMe.txt │ ├── Kindle_for_Android_Patches │ │ ├── kindle_version_4.8.1.10 │ │ │ ├── Notes on the Patch.txt │ │ │ └── kindle4.8.1.10.patch │ │ ├── kindle_version_3.0.1.70 │ │ │ ├── ReadMe_K4Android.txt │ │ │ └── kindle3.0.1.70.patch │ │ ├── kindle_version_3.7.0.108 │ │ │ ├── ReadMe_K4Android.txt │ │ │ └── kindle3.7.0.108.patch │ │ ├── A_Patching_Experience.txt │ │ └── kindle_version_4.0.2.1 │ │ │ └── kindle4.0.2.1.patch │ ├── B_and_N_Download_Helper │ │ ├── BN-Dload.user.js │ │ └── BN-Dload.user_ReadMe.txt │ └── DRM_Key_Scripts │ │ └── Kindle_for_iOS │ │ └── kindleiospidgen.pyw ├── DeDRM_Windows_Application │ ├── DeDRM_App │ │ └── DeDRM_Drop_Target.bat │ └── DeDRM_App_ReadMe.txt ├── Obok_calibre_plugin │ └── obok_plugin_ReadMe.txt ├── DeDRM_calibre_plugin │ └── DeDRM_plugin_ReadMe.txt └── ReadMe_First.txt ├── .gitattributes ├── .gitignore ├── README.md ├── CALIBRE_CLI_INSTRUCTIONS.md └── make_release.py /dedrm_src/plugin-import-name-dedrm.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /obok_src/plugin-import-name-obok_dedrm.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/PkgInfo: -------------------------------------------------------------------------------- 1 | APPLdplt -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM Progress.app/Contents/PkgInfo: -------------------------------------------------------------------------------- 1 | APPL???? -------------------------------------------------------------------------------- /dedrm_src/alfcrypto.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/dedrm_src/alfcrypto.dll -------------------------------------------------------------------------------- /dedrm_src/alfcrypto64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/dedrm_src/alfcrypto64.dll -------------------------------------------------------------------------------- /obok_src/images/obok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/obok_src/images/obok.png -------------------------------------------------------------------------------- /dedrm_src/alfcrypto_src.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/dedrm_src/alfcrypto_src.zip -------------------------------------------------------------------------------- /dedrm_src/libalfcrypto.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/dedrm_src/libalfcrypto.dylib -------------------------------------------------------------------------------- /dedrm_src/libalfcrypto32.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/dedrm_src/libalfcrypto32.so -------------------------------------------------------------------------------- /dedrm_src/libalfcrypto64.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/dedrm_src/libalfcrypto64.so -------------------------------------------------------------------------------- /obok_src/translations/ar.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/obok_src/translations/ar.mo -------------------------------------------------------------------------------- /obok_src/translations/de.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/obok_src/translations/de.mo -------------------------------------------------------------------------------- /obok_src/translations/es.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/obok_src/translations/es.mo -------------------------------------------------------------------------------- /obok_src/translations/nl.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/obok_src/translations/nl.mo -------------------------------------------------------------------------------- /obok_src/translations/pt.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/obok_src/translations/pt.mo -------------------------------------------------------------------------------- /contrib/Other_Tools/Rocket_ebooks/rebhack.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/contrib/Other_Tools/Rocket_ebooks/rebhack.zip -------------------------------------------------------------------------------- /obok_src/obok/__init__.py: -------------------------------------------------------------------------------- 1 | # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai 2 | 3 | __license__ = 'GPL v3' 4 | __docformat__ = 'restructuredtext en' 5 | -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM.app.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/contrib/DeDRM_Macintosh_Application/DeDRM.app.txt -------------------------------------------------------------------------------- /contrib/DeDRM_Windows_Application/DeDRM_App/DeDRM_Drop_Target.bat: -------------------------------------------------------------------------------- 1 | chcp 65001 > nul && set PWD="%~dp0" && cd /d "%~dp0DeDRM_lib" && start /min python DeDRM_App.pyw %* 2 | -------------------------------------------------------------------------------- /contrib/Other_Tools/Scuolabook_DRM/Scuolabook_ReadMe.txt: -------------------------------------------------------------------------------- 1 | The latest Scuolabook tool can be found at Hex's own blog: 2 | https://thisishex.wordpress.com/scuolabook-drm-remover/ 3 | 4 | Harper. -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/MacOS/droplet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/MacOS/droplet -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM.icns -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/description.rtfd/TXT.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1671 2 | {\fonttbl} 3 | {\colortbl;\red255\green255\blue255;} 4 | {\*\expandedcolortbl;;} 5 | } -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/Scripts/main.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/Scripts/main.scpt -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM Progress Source.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM Progress Source.zip -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM Progress.app/Contents/MacOS/DeDRM Progress: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM Progress.app/Contents/MacOS/DeDRM Progress -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM Progress.app/Contents/Resources/DeDRM Progress.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM Progress.app/Contents/Resources/DeDRM Progress.icns -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM Progress.app/Contents/Resources/Scripts/Window.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM Progress.app/Contents/Resources/Scripts/Window.scpt -------------------------------------------------------------------------------- /contrib/Other_Tools/Rocket_ebooks/rebhack_ReadMe.txt: -------------------------------------------------------------------------------- 1 | Rocket eBooks 2 | ============= 3 | 4 | Rocket ebooks (.rb) are no longer sold. 5 | 6 | This is the only archive of tools for decrypting Rocket ebooks that I have been able to find. It is included here without further comment or support. 7 | 8 | — Alf. 9 | -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM Progress.app/Contents/Resources/English.lproj/MainMenu.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM Progress.app/Contents/Resources/English.lproj/MainMenu.nib -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM Progress.app/Contents/Resources/English.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonjchen/DeDRM_tools/master/contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM Progress.app/Contents/Resources/English.lproj/InfoPlist.strings -------------------------------------------------------------------------------- /contrib/Other_Tools/Tetrachroma_FileOpen_ineptpdf/ineptpdf_8.4.51_ReadMe.txt: -------------------------------------------------------------------------------- 1 | ineptpdf 8.4.51 2 | --------------- 3 | 4 | This is a version of the ineptpdf script produced by TetraChroma that can remove, on Windows, "FileOpen" DRM. 5 | 6 | No support for this script is offered at Apprentice Alf's blog. 7 | 8 | Trtrachroma's blog is http://tetrachroma.wordpress.com/ 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /contrib/Other_Tools/Kindle_for_Android_Patches/kindle_version_4.8.1.10/Notes on the Patch.txt: -------------------------------------------------------------------------------- 1 | Notes from UE01 about this patch: 2 | 3 | 1. Revised the “Other_Tools/Kindle_for_Android_Patches/” for Kindle 4.8.1.10 4 | 2. Built Kindle 4.8.1.10 with the PID List added to the About activity 5 | 3. Uninstalled the Amazon/Play-store version and installed the patched version 6 | 4. Signed in to Amazon 7 | 5. Opened the book 8 | 6. Did Info > About > PID List and copied the PIDs to Calibre’s Plugins>File type > DeDRM > Mobipocket dialog 9 | 7. **Crucial** copied the PRC file to the PC (because the file’s checksum has changed since it was last copied) 10 | 8. In Calibre, Add Books (from a single directory) 11 | 12 | -------------------------------------------------------------------------------- /dedrm_src/pycrypto_des.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab 3 | 4 | 5 | def load_pycrypto(): 6 | try : 7 | from Crypto.Cipher import DES as _DES 8 | except: 9 | return None 10 | 11 | class DES(object): 12 | def __init__(self, key): 13 | if len(key) != 8 : 14 | raise Error('DES improper key used') 15 | self.key = key 16 | self._des = _DES.new(key,_DES.MODE_ECB) 17 | def desdecrypt(self, data): 18 | return self._des.decrypt(data) 19 | def decrypt(self, data): 20 | if not data: 21 | return '' 22 | i = 0 23 | result = [] 24 | while i < len(data): 25 | block = data[i:i+8] 26 | processed_block = self.desdecrypt(block) 27 | result.append(processed_block) 28 | i += 8 29 | return ''.join(result) 30 | return DES 31 | -------------------------------------------------------------------------------- /contrib/Other_Tools/B_and_N_Download_Helper/BN-Dload.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name BN-Dload 3 | // @namespace http://www.mailinator.com/J-man 4 | // @include https://mynook.barnesandnoble.com/library.html* 5 | // @grant none 6 | // @version 20121119 7 | // ==/UserScript== 8 | 9 | function doIt() { 10 | if ($('#adl1').length == 0) { 11 | $('[action$="deleteItem"]').each(function(index) { 12 | if ($(this).parent().find('[action$="EDSDeliverItem.aspx"]').length == 0) { 13 | var delid = $(this).find('input').attr('value'); 14 | $(this).after('
'); 15 | } 16 | }); 17 | 18 | } 19 | 20 | setTimeout (function() { 21 | doIt(); 22 | }, 3000 ); 23 | } 24 | 25 | doIt(); 26 | 27 | -------------------------------------------------------------------------------- /dedrm_src/encodebase64.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # base64.py, version 1.0 5 | # Copyright © 2010 Apprentice Alf 6 | 7 | # Released under the terms of the GNU General Public Licence, version 3 or 8 | # later. 9 | 10 | # Revision history: 11 | # 1 - Initial release. To allow Applescript to do base64 encoding 12 | 13 | """ 14 | Provide base64 encoding. 15 | """ 16 | 17 | from __future__ import with_statement 18 | 19 | __license__ = 'GPL v3' 20 | 21 | import sys 22 | import os 23 | import base64 24 | 25 | def usage(progname): 26 | print "Applies base64 encoding to the supplied file, sending to standard output" 27 | print "Usage:" 28 | print " %s " % progname 29 | 30 | def cli_main(argv=sys.argv): 31 | progname = os.path.basename(argv[0]) 32 | 33 | if len(argv)<2: 34 | usage(progname) 35 | sys.exit(2) 36 | 37 | keypath = argv[1] 38 | with open(keypath, 'rb') as f: 39 | keyder = f.read() 40 | print keyder.encode('base64') 41 | return 0 42 | 43 | 44 | if __name__ == '__main__': 45 | sys.exit(cli_main()) 46 | -------------------------------------------------------------------------------- /obok_src/obok_dedrm_Help.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Obok DeDRM Plugin Configuration 6 | 7 | 8 | 9 | 10 |

Obok DeDRM Plugin

11 |

(version 3.1.3)

12 | 13 |

Installation:

14 | 15 |

The ususal method of Preferences -> Plugins -> Load plugin from file.

16 | 17 | 18 |

Configuration:

19 | 20 |

There is no configuration (other than to choose what menus to add obok to)

21 | 22 | 23 |

Troubleshooting:

24 | 25 |

If you find that it’s not working for you , you can save a lot of time by using the plugin with Calibre in debug mode. This will print out a lot of helpful info that can be copied into any online help requests.

26 | 27 |

Open a command prompt (terminal window) and type "calibre-debug -g" (without the quotes). Calibre will launch, and you can use the plugin the usual way. The debug info will be output to the original command prompt (terminal window). Copy the resulting output and paste it into the comment you make at Apprentice Alf's blog.

28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /dedrm_src/scrolltextwidget.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab 3 | 4 | import Tkinter 5 | import Tkconstants 6 | 7 | # basic scrolled text widget 8 | class ScrolledText(Tkinter.Text): 9 | def __init__(self, master=None, **kw): 10 | self.frame = Tkinter.Frame(master) 11 | self.vbar = Tkinter.Scrollbar(self.frame) 12 | self.vbar.pack(side=Tkconstants.RIGHT, fill=Tkconstants.Y) 13 | kw.update({'yscrollcommand': self.vbar.set}) 14 | Tkinter.Text.__init__(self, self.frame, **kw) 15 | self.pack(side=Tkconstants.LEFT, fill=Tkconstants.BOTH, expand=True) 16 | self.vbar['command'] = self.yview 17 | # Copy geometry methods of self.frame without overriding Text 18 | # methods = hack! 19 | text_meths = vars(Tkinter.Text).keys() 20 | methods = vars(Tkinter.Pack).keys() + vars(Tkinter.Grid).keys() + vars(Tkinter.Place).keys() 21 | methods = set(methods).difference(text_meths) 22 | for m in methods: 23 | if m[0] != '_' and m != 'config' and m != 'configure': 24 | setattr(self, m, getattr(self.frame, m)) 25 | 26 | def __str__(self): 27 | return str(self.frame) 28 | -------------------------------------------------------------------------------- /contrib/Other_Tools/B_and_N_Download_Helper/BN-Dload.user_ReadMe.txt: -------------------------------------------------------------------------------- 1 | INTRODUCTION 2 | ============ 3 | 4 | To obtain unencrypted content from the B&N, you have to download it directly from the website. Unrooted Nook devices will not let you save your content to your PC. 5 | 6 | If the downloaded file is encrypted, install and configure the ignoble plugin in Calibre to decrypt that. 7 | 8 | 9 | DOWNLOAD HIDDEN FILES FROM B&N 10 | ------------------------------ 11 | 12 | Some content is not downloadable from the B&N website, notably magazines. A Greasemonkey script (details below) modifies the myNook page of the Barnes and Noble website to show a download button for normally non-downloadable content. This will work until Barnes & Noble changes their website. 13 | 14 | Prerequisites 15 | ------------- 16 | 1) Firefox: http://www.getfirefox.com 17 | 2) Greasemokey extension: https://addons.mozilla.org/nl/firefox/addon/greasemonkey/ 18 | 19 | One time installation 20 | --------------------- 21 | 1) Install Firefox if not already done so 22 | 2) Follow the above link to GreaseMonkey and click Add to Firefox 23 | 3) Restart Firefox 24 | 4) Go to http://userscripts.org/scripts/source/152985.user.js 25 | 5) A popup should appear, stating you are about to install a GreaseMonkey user script. 26 | 6) Click on install 27 | 28 | Use 29 | --- 30 | 1) Log in into your B&N account 31 | 2) Go to MyNook 32 | 3) An “Alternative download” should appear next to normally non-downloadable content. Note that this will not work for content such as Nook applications, and some children books. 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.pyc 4 | 5 | # Distribution / packaging 6 | .Python 7 | env/ 8 | build/ 9 | develop-eggs/ 10 | dist/ 11 | downloads/ 12 | eggs/ 13 | lib64/ 14 | parts/ 15 | sdist/ 16 | var/ 17 | *.egg-info/ 18 | .installed.cfg 19 | *.egg 20 | 21 | # PyInstaller 22 | # Usually these files are written by a python script from a template 23 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 24 | *.manifest 25 | *.spec 26 | 27 | # Installer logs 28 | pip-log.txt 29 | pip-delete-this-directory.txt 30 | 31 | # Unit test / coverage reports 32 | htmlcov/ 33 | .tox/ 34 | .coverage 35 | .cache 36 | nosetests.xml 37 | coverage.xml 38 | 39 | # Translations 40 | *.pot 41 | 42 | # Django stuff: 43 | *.log 44 | 45 | # Sphinx documentation 46 | docs/_build/ 47 | 48 | # PyBuilder 49 | target/ 50 | 51 | # ========================= 52 | # Operating System Files 53 | # ========================= 54 | 55 | # OSX 56 | # ========================= 57 | 58 | .DS_Store 59 | .AppleDouble 60 | .LSOverride 61 | 62 | # Thumbnails 63 | ._* 64 | 65 | # Files that might appear on external disk 66 | .Spotlight-V100 67 | .Trashes 68 | 69 | # Directories potentially created on remote AFP share 70 | .AppleDB 71 | .AppleDesktop 72 | Network Trash Folder 73 | Temporary Items 74 | .apdisk 75 | 76 | # Windows 77 | # ========================= 78 | 79 | # Windows image file caches 80 | Thumbs.db 81 | ehthumbs.db 82 | 83 | # Folder config file 84 | Desktop.ini 85 | 86 | # Recycle Bin used on file shares 87 | $RECYCLE.BIN/ 88 | 89 | # Windows Installer files 90 | *.cab 91 | *.msi 92 | *.msm 93 | *.msp 94 | 95 | # Windows shortcuts 96 | *.lnk 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DeDRM_tools 2 | DeDRM tools for ebooks 3 | 4 | This is a repository of all the scripts and other tools for removing DRM from ebooks that I could find, committed in date order as best as I could manage. (Except for the Requiem tools for Apple's iBooks, and Convert LIT for Microsoft's .lit ebooks.) 5 | 6 | Mostly it tracks the tools releases by Apprentice Alf, athough it also includes the individual tools and their histories from before Alf had a blog. 7 | 8 | Users should download the latest zip archive. 9 | Developers might be interested in forking the repository, as it contains unzipped versions of those tools that are zipped, and text versions of the AppleScripts, to make the changes over time easier to follow. 10 | 11 | For the latest Amazon KFX format, users of the calibre plugin should also install the KFX Input plugin from the standard calibre plugin menu. It's also available from the MobileRead thread here: https://www.mobileread.com/forums/showthread.php?t=291290 12 | 13 | I welcome contributions from others to improve these tools, from expanding the range of books handled, improving key retrieval, to just general bug fixes, speed improvements and UI enhancements. 14 | 15 | I urge people to read the FAQs. But to cover the most common: Use ADE 2.0.1 to be sure not to get the new DRM scheme that these tools can't handle. Use Kindle for Mac/PC 1.24 or earlier, the tools don't currently work with 1.25 or later. Do remember to unzip the downloaded archive to get the plugin. You can't load the whole archive into calibre. 16 | 17 | My special thanks to all those developers who have done the hard work of reverse engineering to provide the initial tools. 18 | 19 | Apprentice Harper. 20 | -------------------------------------------------------------------------------- /dedrm_src/utilities.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import with_statement 5 | 6 | __license__ = 'GPL v3' 7 | 8 | DETAILED_MESSAGE = \ 9 | 'You have personal information stored in this plugin\'s customization '+ \ 10 | 'string from a previous version of this plugin.\n\n'+ \ 11 | 'This new version of the plugin can convert that info '+ \ 12 | 'into key data that the new plugin can then use (which doesn\'t '+ \ 13 | 'require personal information to be stored/displayed in an insecure '+ \ 14 | 'manner like the old plugin did).\n\nIf you choose NOT to migrate this data at this time '+ \ 15 | 'you will be prompted to save that personal data to a file elsewhere; and you\'ll have '+ \ 16 | 'to manually re-configure this plugin with your information.\n\nEither way... ' + \ 17 | 'this new version of the plugin will not be responsible for storing that personal '+ \ 18 | 'info in plain sight any longer.' 19 | 20 | def uStrCmp (s1, s2, caseless=False): 21 | import unicodedata as ud 22 | str1 = s1 if isinstance(s1, unicode) else unicode(s1) 23 | str2 = s2 if isinstance(s2, unicode) else unicode(s2) 24 | if caseless: 25 | return ud.normalize('NFC', str1.lower()) == ud.normalize('NFC', str2.lower()) 26 | else: 27 | return ud.normalize('NFC', str1) == ud.normalize('NFC', str2) 28 | 29 | def parseCustString(keystuff): 30 | userkeys = [] 31 | ar = keystuff.split(':') 32 | for i in ar: 33 | try: 34 | name, ccn = i.split(',') 35 | # Generate Barnes & Noble EPUB user key from name and credit card number. 36 | userkeys.append(generate_key(name, ccn)) 37 | except: 38 | pass 39 | return userkeys 40 | -------------------------------------------------------------------------------- /CALIBRE_CLI_INSTRUCTIONS.md: -------------------------------------------------------------------------------- 1 | # Using the DeDRM plugin with the Calibre command line interface 2 | 3 | If you prefer the Calibre CLI instead of the GUI, follow this guide to 4 | install and use the DeDRM plugin. 5 | 6 | This guide assumes you are on Linux, but it may very well work on other 7 | platforms. 8 | 9 | ## Step-by-step Tutorial 10 | 11 | #### Install Calibre 12 | - Follow [Calibre's installation instructions](https://calibre-ebook.com/download_linux) 13 | 14 | #### Install plugins 15 | - Download the DeDRM `.zip` archive from DeDRM_tools' 16 | [latest release](https://github.com/apprenticeharper/DeDRM_tools/releases/latest). 17 | Then unzip it. 18 | - Add the DeDRM plugin to Calibre: 19 | ``` 20 | cd *the unzipped DeDRM_tools folder* 21 | calibre-customize --add DeDRM_calibre_plugin/DeDRM_plugin.zip 22 | ``` 23 | - Add the Obok plugin: 24 | ``` 25 | calibre-customize --add Obok_calibre_plugin/obok_plugin.zip 26 | ``` 27 | 28 | #### Enter your keys 29 | - Figure out what format DeDRM wants your key in by looking in 30 | [the code that handles that](src/prefs.py). 31 | - For Kindle eInk devices, DeDRM expects you to put a list of serial 32 | numbers in the `serials` field: `"serials": ["012345689abcdef"]` or 33 | `"serials": ["1111111111111111", "2222222222222222"]`. 34 | - Now add your keys to `$CALIBRE_CONFIG_DIRECTORY/plugins/dedrm.json`. 35 | 36 | #### Import your books 37 | - Make a library folder 38 | ``` 39 | mkdir library 40 | ``` 41 | - Add your book(s) with this command: 42 | ``` 43 | calibredb add /path/to/book.format --with-library=library 44 | ``` 45 | 46 | The DRM should be removed from your book, which you can find in the `library` 47 | folder. 48 | -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM Progress.app/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 10K549 7 | CFBundleDevelopmentRegion 8 | English 9 | CFBundleExecutable 10 | DeDRM Progress 11 | CFBundleGetInfoString 12 | DeDRM Progress 1.1, Written 2010, 2012 by Apprentice Alf and others. 13 | CFBundleIconFile 14 | DeDRM Progress 15 | CFBundleIdentifier 16 | com.apprenticealf.DeDRMProgress 17 | CFBundleInfoDictionaryVersion 18 | 6.0 19 | CFBundleName 20 | DeDRM Progress 21 | CFBundlePackageType 22 | APPL 23 | CFBundleShortVersionString 24 | 1.1 25 | CFBundleSignature 26 | ???? 27 | CFBundleVersion 28 | 1.0 29 | DTCompiler 30 | 4.0 31 | DTPlatformBuild 32 | 10M2518 33 | DTPlatformVersion 34 | PG 35 | DTSDKBuild 36 | 8S2167 37 | DTSDKName 38 | macosx10.4 39 | DTXcode 40 | 0400 41 | DTXcodeBuild 42 | 10M2518 43 | NSAppleScriptEnabled 44 | YES 45 | NSMainNibFile 46 | MainMenu 47 | NSPrincipalClass 48 | NSApplication 49 | 50 | 51 | -------------------------------------------------------------------------------- /dedrm_src/DeDRM_Mobipocket PID_Help.htm: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | Managing Mobipocket PIDs 9 | 16 | 17 | 18 | 19 | 20 |

Managing Mobipocket PIDs

21 | 22 |

If you have upgraded from an earlier version of the plugin, any existing Mobipocket PIDs will have been automatically imported, so you might not need to do any more configuration.

23 | 24 | 25 |

Creating New Mobipocket PIDs:

26 | 27 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering a new Mobipocket PID.

28 | 31 | 32 |

Click the OK button to save the PID. Or Cancel if you didn’t want to enter a PID.

33 | 34 |

Deleting Mobipocket PIDs:

35 | 36 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted Mobipocket PID from the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

37 | 38 |

Once done creating/deleting PIDs, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /dedrm_src/DeDRM_EInk Kindle Serial Number_Help.htm: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | Managing eInk Kindle serial numbers 9 | 16 | 17 | 18 | 19 | 20 |

Managing eInk Kindle serial numbers

21 | 22 |

If you have upgraded from an earlier version of the plugin, any existing eInk Kindle serial numbers will have been automatically imported, so you might not need to do any more configuration.

23 | 24 |

Please note that Kindle serial numbers are only valid keys for eInk Kindles like the Kindle Touch and PaperWhite. The Kindle Fire and Fire HD do not use their serial number for DRM and it is useless to enter those serial numbers.

25 | 26 |

Creating New Kindle serial numbers:

27 | 28 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering a new Kindle serial number.

29 | 32 | 33 |

Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.

34 | 35 |

Deleting Kindle serial numbers:

36 | 37 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted Kindle serial number from the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

38 | 39 |

Once done creating/deleting serial numbers, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /make_release.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # code: utf-8 3 | 4 | ''' 5 | A wrapper script to generate zip files for GitHub releases. 6 | 7 | This script tends to be compatible with both Python 2 and Python 3. 8 | ''' 9 | 10 | from __future__ import print_function 11 | 12 | import os 13 | import shutil 14 | 15 | 16 | DEDRM_SRC_DIR = 'dedrm_src' 17 | OBOK_SRC_DIR = 'obok_src' 18 | SHELLS_BASE = 'contrib' 19 | 20 | def make_calibre_plugin(): 21 | calibre_plugin_dir = os.path.join(SHELLS_BASE, 'DeDRM_calibre_plugin') 22 | core_dir = os.path.join(calibre_plugin_dir, 'DeDRM_plugin') 23 | 24 | shutil.copytree(DEDRM_SRC_DIR, core_dir) 25 | shutil.make_archive(core_dir, 'zip', core_dir) 26 | shutil.rmtree(core_dir) 27 | 28 | 29 | def make_obok_plugin(): 30 | obok_plugin_dir = os.path.join(SHELLS_BASE, 'Obok_calibre_plugin') 31 | core_dir = os.path.join(obok_plugin_dir, 'obok_plugin') 32 | 33 | shutil.copytree(OBOK_SRC_DIR, core_dir) 34 | shutil.make_archive(core_dir, 'zip', core_dir) 35 | shutil.rmtree(core_dir) 36 | 37 | 38 | def make_windows_app(): 39 | windows_app_dir = os.path.join(SHELLS_BASE, 'DeDRM_Windows_Application') 40 | core_dir = os.path.join(windows_app_dir, 'DeDRM_App', 'DeDRM_lib', 'lib') 41 | 42 | # delete any existing core_dir 43 | try: 44 | shutil.rmtree(core_dir) 45 | except OSError: 46 | pass 47 | 48 | shutil.copytree(DEDRM_SRC_DIR, core_dir) 49 | 50 | 51 | def make_macos_app(): 52 | macos_app_dir = os.path.join(SHELLS_BASE, 'DeDRM_Macintosh_Application') 53 | core_dir = os.path.join(macos_app_dir, 'DeDRM.app', 'Contents', 'Resources') 54 | 55 | # Resources already exists - copy contents to contents. 56 | _, dirs, files = next(os.walk(DEDRM_SRC_DIR)) 57 | for name in dirs: 58 | shutil.copyfile( 59 | os.path.join(DEDRM_SRC_DIR, name), 60 | os.path.join(core_dir, name) 61 | ) 62 | for name in files: 63 | shutil.copy2( 64 | os.path.join(DEDRM_SRC_DIR, name), 65 | os.path.join(core_dir, name) 66 | ) 67 | 68 | 69 | def make_release(version): 70 | make_calibre_plugin() 71 | make_windows_app() 72 | make_macos_app() 73 | make_obok_plugin() 74 | 75 | release_name = 'DeDRM_tools_{}'.format(version) 76 | return shutil.make_archive(release_name, 'zip', SHELLS_BASE) 77 | 78 | 79 | if __name__ == '__main__': 80 | import sys 81 | try: 82 | version = sys.argv[1] 83 | except IndexError: 84 | raise SystemExit('Usage: {} version'.format(__file__)) 85 | 86 | print(make_release(version)) 87 | -------------------------------------------------------------------------------- /dedrm_src/argv_utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys, os 5 | import locale 6 | import codecs 7 | 8 | # get sys.argv arguments and encode them into utf-8 9 | def unicode_argv(): 10 | if sys.platform.startswith('win'): 11 | # Uses shell32.GetCommandLineArgvW to get sys.argv as a list of Unicode 12 | # strings. 13 | 14 | # Versions 2.x of Python don't support Unicode in sys.argv on 15 | # Windows, with the underlying Windows API instead replacing multi-byte 16 | # characters with '?'. 17 | 18 | 19 | from ctypes import POINTER, byref, cdll, c_int, windll 20 | from ctypes.wintypes import LPCWSTR, LPWSTR 21 | 22 | GetCommandLineW = cdll.kernel32.GetCommandLineW 23 | GetCommandLineW.argtypes = [] 24 | GetCommandLineW.restype = LPCWSTR 25 | 26 | CommandLineToArgvW = windll.shell32.CommandLineToArgvW 27 | CommandLineToArgvW.argtypes = [LPCWSTR, POINTER(c_int)] 28 | CommandLineToArgvW.restype = POINTER(LPWSTR) 29 | 30 | cmd = GetCommandLineW() 31 | argc = c_int(0) 32 | argv = CommandLineToArgvW(cmd, byref(argc)) 33 | if argc.value > 0: 34 | # Remove Python executable and commands if present 35 | start = argc.value - len(sys.argv) 36 | return [argv[i] for i in 37 | xrange(start, argc.value)] 38 | # if we don't have any arguments at all, just pass back script name 39 | # this should never happen 40 | return [u"DeDRM.py"] 41 | else: 42 | argvencoding = sys.stdin.encoding 43 | if argvencoding == None: 44 | argvencoding = "utf-8" 45 | return [arg if (type(arg) == unicode) else unicode(arg,argvencoding) for arg in sys.argv] 46 | 47 | 48 | def add_cp65001_codec(): 49 | try: 50 | codecs.lookup('cp65001') 51 | except LookupError: 52 | codecs.register( 53 | lambda name: name == 'cp65001' and codecs.lookup('utf-8') or None) 54 | return 55 | 56 | 57 | def set_utf8_default_encoding(): 58 | if sys.getdefaultencoding() == 'utf-8': 59 | return 60 | 61 | # Regenerate setdefaultencoding. 62 | reload(sys) 63 | sys.setdefaultencoding('utf-8') 64 | 65 | for attr in dir(locale): 66 | if attr[0:3] != 'LC_': 67 | continue 68 | aref = getattr(locale, attr) 69 | try: 70 | locale.setlocale(aref, '') 71 | except locale.Error: 72 | continue 73 | try: 74 | lang = locale.getlocale(aref)[0] 75 | except (TypeError, ValueError): 76 | continue 77 | if lang: 78 | try: 79 | locale.setlocale(aref, (lang, 'UTF-8')) 80 | except locale.Error: 81 | os.environ[attr] = lang + '.UTF-8' 82 | try: 83 | locale.setlocale(locale.LC_ALL, '') 84 | except locale.Error: 85 | pass 86 | return 87 | 88 | 89 | -------------------------------------------------------------------------------- /obok_src/translations/de.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: obok\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2014-10-19 10:28+0200\n" 11 | "PO-Revision-Date: 2014-10-23 14:43+0100\n" 12 | "Last-Translator: \n" 13 | "Language-Team: friends of obok\n" 14 | "Language: de\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 19 | "X-Generator: Poedit 1.6.10\n" 20 | 21 | #: common_utils.py:220 22 | msgid "Help" 23 | msgstr "Hilfe" 24 | 25 | #: common_utils.py:229 utilities.py:207 26 | msgid "Restart required" 27 | msgstr "Neustart erforderlich" 28 | 29 | #: common_utils.py:230 utilities.py:208 30 | msgid "" 31 | "Title image not found - you must restart Calibre before using this plugin!" 32 | msgstr "" 33 | "Das Abbild wurde nicht gefunden. - vor der Verwendung dieses Calibre Plugin " 34 | "is ein Neustart erforderlich!" 35 | 36 | #: common_utils.py:316 37 | msgid "Undefined" 38 | msgstr "Undefiniert" 39 | 40 | #: config.py:25 41 | msgid "" 42 | "

Default behavior when duplicates are detected. None of the choices will " 43 | "cause calibre ebooks to be overwritten" 44 | msgstr "" 45 | "

Standardverhalten, wenn Duplikate erkannt werden. Keine der " 46 | "Entscheidungen werden ebooks verursachen das sie überschrieben werden." 47 | 48 | #: dialogs.py:58 49 | msgid "Obok DeDRM" 50 | msgstr "Obok DeDRM" 51 | 52 | #: dialogs.py:68 53 | msgid "Help" 54 | msgstr "Hilfe" 55 | 56 | #: dialogs.py:82 57 | msgid "Select All" 58 | msgstr "Alles markieren" 59 | 60 | #: dialogs.py:83 61 | msgid "Select all books to add them to the calibre library." 62 | msgstr "Wählen Sie alle Bücher, um sie zu Calibre Bibliothek hinzuzufügen." 63 | 64 | #: dialogs.py:85 65 | msgid "All with DRM" 66 | msgstr "Alle mit DRM" 67 | 68 | #: dialogs.py:86 69 | msgid "Select all books with DRM." 70 | msgstr "Wählen Sie alle Bücher mit DRM." 71 | 72 | #: dialogs.py:88 73 | msgid "All DRM free" 74 | msgstr "Alle ohne DRM" 75 | 76 | #: dialogs.py:89 77 | msgid "Select all books without DRM." 78 | msgstr "Wählen Sie alle Bücher ohne DRM." 79 | 80 | #: dialogs.py:139 81 | msgid "Title" 82 | msgstr "Titel" 83 | 84 | #: dialogs.py:139 85 | msgid "Author" 86 | msgstr "Autor" 87 | 88 | #: dialogs.py:139 89 | msgid "Series" 90 | msgstr "Reihe" 91 | 92 | #: dialogs.py:362 93 | msgid "Copy to clipboard" 94 | msgstr "In Zwischenablage kopieren" 95 | 96 | #: dialogs.py:390 97 | msgid "View Report" 98 | msgstr "Bericht anzeigen" 99 | 100 | #: __init__.py:24 101 | msgid "Removes DRM from Kobo kepubs and adds them to the library." 102 | msgstr "Entfernt DRM von Kobo kepubs und fügt sie zu Bibliothek hinzu." 103 | -------------------------------------------------------------------------------- /obok_src/translations/nl.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: obok\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2014-10-19 10:28+0200\n" 11 | "PO-Revision-Date: 2014-10-23 14:08+0100\n" 12 | "Last-Translator: \n" 13 | "Language-Team: friends of obok\n" 14 | "Language: nl\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 19 | "X-Generator: Poedit 1.6.10\n" 20 | 21 | #: common_utils.py:220 22 | msgid "Help" 23 | msgstr "Help" 24 | 25 | #: common_utils.py:229 utilities.py:207 26 | msgid "Restart required" 27 | msgstr "Opnieuw opstarten vereist" 28 | 29 | #: common_utils.py:230 utilities.py:208 30 | msgid "" 31 | "Title image not found - you must restart Calibre before using this plugin!" 32 | msgstr "" 33 | "Afbeelding niet gevonden. - Calibre moet opnieuw opgestart worden voordat " 34 | "deze plugin kan worden gebruikt!" 35 | 36 | #: common_utils.py:316 37 | msgid "Undefined" 38 | msgstr "Niet gedefinieerd" 39 | 40 | #: config.py:25 41 | msgid "" 42 | "

Default behavior when duplicates are detected. None of the choices will " 43 | "cause calibre ebooks to be overwritten" 44 | msgstr "" 45 | "

Standaard gedrag wanneer er duplicaten worden geconstateerd. Geen van de " 46 | "opties zal reeds bestaande ebooks in de Calibre bibliotheek overschrijven." 47 | 48 | #: dialogs.py:58 49 | msgid "Obok DeDRM" 50 | msgstr "Obok DeDRM" 51 | 52 | #: dialogs.py:68 53 | msgid "Help" 54 | msgstr "Help" 55 | 56 | #: dialogs.py:82 57 | msgid "Select All" 58 | msgstr "Alles selecteren" 59 | 60 | #: dialogs.py:83 61 | msgid "Select all books to add them to the calibre library." 62 | msgstr "Alle boeken selecteren om ze aan de Calibre bibliotheek toe te voegen." 63 | 64 | #: dialogs.py:85 65 | msgid "All with DRM" 66 | msgstr "Alle met DRM" 67 | 68 | #: dialogs.py:86 69 | msgid "Select all books with DRM." 70 | msgstr "Alle boeken met DRM selecteren." 71 | 72 | #: dialogs.py:88 73 | msgid "All DRM free" 74 | msgstr "Alle zonder DRM" 75 | 76 | #: dialogs.py:89 77 | msgid "Select all books without DRM." 78 | msgstr "Alle boeken zonder DRM selecteren." 79 | 80 | #: dialogs.py:139 81 | msgid "Title" 82 | msgstr "Titel" 83 | 84 | #: dialogs.py:139 85 | msgid "Author" 86 | msgstr "Auteur" 87 | 88 | #: dialogs.py:139 89 | msgid "Series" 90 | msgstr "Reeks/serie" 91 | 92 | #: dialogs.py:362 93 | msgid "Copy to clipboard" 94 | msgstr "Naar het Klembord kopiëren" 95 | 96 | #: dialogs.py:390 97 | msgid "View Report" 98 | msgstr "Rapport weergeven" 99 | 100 | #: __init__.py:24 101 | msgid "Removes DRM from Kobo kepubs and adds them to the library." 102 | msgstr "Verwijdert de DRM van Kobo kepubs en voegt ze toe aan de bibliotheek." 103 | -------------------------------------------------------------------------------- /obok_src/obok/legacy_obok.py: -------------------------------------------------------------------------------- 1 | # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai 2 | 3 | __license__ = 'GPL v3' 4 | __docformat__ = 'restructuredtext en' 5 | 6 | import os, sys 7 | import binascii, hashlib, re, string 8 | 9 | class legacy_obok(object): 10 | def __init__(self): 11 | self._userkey = '' 12 | 13 | @property 14 | def get_legacy_cookie_id(self): 15 | if self._userkey != '': 16 | return self._userkey 17 | self._userkey = self.__oldcookiedeviceid() 18 | return self._userkey 19 | 20 | def __bytearraytostring(self, bytearr): 21 | wincheck = re.match('@ByteArray\\((.+)\\)', bytearr) 22 | if wincheck: 23 | return wincheck.group(1) 24 | return bytearr 25 | 26 | def plist_to_dictionary(self, filename): 27 | from subprocess import Popen, PIPE 28 | from plistlib import readPlistFromString 29 | 'Pipe the binary plist through plutil and parse the xml output' 30 | with open(filename, 'rb') as f: 31 | content = f.read() 32 | args = ['plutil', '-convert', 'xml1', '-o', '-', '--', '-'] 33 | p = Popen(args, stdin=PIPE, stdout=PIPE) 34 | p.stdin.write(content) 35 | out, err = p.communicate() 36 | return readPlistFromString(out) 37 | 38 | def __oldcookiedeviceid(self): 39 | '''Optionally attempt to get a device id using the old cookie method. 40 | Must have _winreg installed on Windows machines for successful key retrieval.''' 41 | wsuid = '' 42 | pwsdid = '' 43 | try: 44 | if sys.platform.startswith('win'): 45 | import _winreg 46 | regkey_browser = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, 'Software\\Kobo\\Kobo Desktop Edition\\Browser') 47 | cookies = _winreg.QueryValueEx(regkey_browser, 'cookies') 48 | bytearrays = cookies[0] 49 | elif sys.platform.startswith('darwin'): 50 | prefs = os.path.join(os.environ['HOME'], 'Library/Preferences/com.kobo.Kobo Desktop Edition.plist') 51 | cookies = self.plist_to_dictionary(prefs) 52 | bytearrays = cookies['Browser.cookies'] 53 | for bytearr in bytearrays: 54 | cookie = self.__bytearraytostring(bytearr) 55 | wsuidcheck = re.match("^wsuid=([0-9a-f-]+)", cookie) 56 | if(wsuidcheck): 57 | wsuid = wsuidcheck.group(1) 58 | pwsdidcheck = re.match('^pwsdid=([0-9a-f-]+)', cookie) 59 | if (pwsdidcheck): 60 | pwsdid = pwsdidcheck.group(1) 61 | if (wsuid == '' or pwsdid == ''): 62 | return None 63 | preuserkey = string.join((pwsdid, wsuid), '') 64 | userkey = hashlib.sha256(preuserkey).hexdigest() 65 | return binascii.a2b_hex(userkey[32:]) 66 | except KeyError: 67 | print ('No "cookies" key found in Kobo plist: no legacy user key found.') 68 | return None 69 | except: 70 | print ('Error parsing Kobo plist: no legacy user key found.') 71 | return None 72 | -------------------------------------------------------------------------------- /obok_src/__init__.py: -------------------------------------------------------------------------------- 1 | # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai 2 | from __future__ import (unicode_literals, division, absolute_import, 3 | print_function) 4 | 5 | __license__ = 'GPL v3' 6 | __docformat__ = 'restructuredtext en' 7 | 8 | ##################################################################### 9 | # Plug-in base class 10 | ##################################################################### 11 | 12 | from calibre.customize import InterfaceActionBase 13 | 14 | try: 15 | load_translations() 16 | except NameError: 17 | pass # load_translations() added in calibre 1.9 18 | 19 | PLUGIN_NAME = 'Obok DeDRM' 20 | PLUGIN_SAFE_NAME = PLUGIN_NAME.strip().lower().replace(' ', '_') 21 | PLUGIN_DESCRIPTION = _('Removes DRM from Kobo kepubs and adds them to the library.') 22 | PLUGIN_VERSION_TUPLE = (6, 5, 4) 23 | PLUGIN_VERSION = '.'.join([str(x) for x in PLUGIN_VERSION_TUPLE]) 24 | HELPFILE_NAME = PLUGIN_SAFE_NAME + '_Help.htm' 25 | PLUGIN_AUTHORS = 'Anon' 26 | ##################################################################### 27 | 28 | class ObokDeDRMAction(InterfaceActionBase): 29 | 30 | name = PLUGIN_NAME 31 | description = PLUGIN_DESCRIPTION 32 | supported_platforms = ['windows', 'osx', 'linux' ] 33 | author = PLUGIN_AUTHORS 34 | version = PLUGIN_VERSION_TUPLE 35 | minimum_calibre_version = (1, 0, 0) 36 | 37 | #: This field defines the GUI plugin class that contains all the code 38 | #: that actually does something. Its format is module_path:class_name 39 | #: The specified class must be defined in the specified module. 40 | actual_plugin = 'calibre_plugins.'+PLUGIN_SAFE_NAME+'.action:InterfacePluginAction' 41 | 42 | def is_customizable(self): 43 | ''' 44 | This method must return True to enable customization via 45 | Preferences->Plugins 46 | ''' 47 | return True 48 | 49 | def config_widget(self): 50 | ''' 51 | Implement this method and :meth:`save_settings` in your plugin to 52 | use a custom configuration dialog. 53 | 54 | This method, if implemented, must return a QWidget. The widget can have 55 | an optional method validate() that takes no arguments and is called 56 | immediately after the user clicks OK. Changes are applied if and only 57 | if the method returns True. 58 | 59 | If for some reason you cannot perform the configuration at this time, 60 | return a tuple of two strings (message, details), these will be 61 | displayed as a warning dialog to the user and the process will be 62 | aborted. 63 | 64 | The base class implementation of this method raises NotImplementedError 65 | so by default no user configuration is possible. 66 | ''' 67 | if self.actual_plugin_: 68 | from calibre_plugins.obok_dedrm.config import ConfigWidget 69 | return ConfigWidget(self.actual_plugin_) 70 | 71 | def save_settings(self, config_widget): 72 | ''' 73 | Save the settings specified by the user with config_widget. 74 | ''' 75 | config_widget.save_settings() 76 | -------------------------------------------------------------------------------- /dedrm_src/activitybar.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import Tkinter 3 | import Tkconstants 4 | 5 | class ActivityBar(Tkinter.Frame): 6 | 7 | def __init__(self, master, length=300, height=20, barwidth=15, interval=50, bg='white', fillcolor='orchid1',\ 8 | bd=2, relief=Tkconstants.GROOVE, *args, **kw): 9 | Tkinter.Frame.__init__(self, master, bg=bg, width=length, height=height, *args, **kw) 10 | self._master = master 11 | self._interval = interval 12 | self._maximum = length 13 | self._startx = 0 14 | self._barwidth = barwidth 15 | self._bardiv = length / barwidth 16 | if self._bardiv < 10: 17 | self._bardiv = 10 18 | stopx = self._startx + self._barwidth 19 | if stopx > self._maximum: 20 | stopx = self._maximum 21 | # self._canv = Tkinter.Canvas(self, bg=self['bg'], width=self['width'], height=self['height'],\ 22 | # highlightthickness=0, relief='flat', bd=0) 23 | self._canv = Tkinter.Canvas(self, bg=self['bg'], width=self['width'], height=self['height'],\ 24 | highlightthickness=0, relief=relief, bd=bd) 25 | self._canv.pack(fill='both', expand=1) 26 | self._rect = self._canv.create_rectangle(0, 0, self._canv.winfo_reqwidth(), self._canv.winfo_reqheight(), fill=fillcolor, width=0) 27 | 28 | self._set() 29 | self.bind('', self._update_coords) 30 | self._running = False 31 | 32 | def _update_coords(self, event): 33 | '''Updates the position of the rectangle inside the canvas when the size of 34 | the widget gets changed.''' 35 | # looks like we have to call update_idletasks() twice to make sure 36 | # to get the results we expect 37 | self._canv.update_idletasks() 38 | self._maximum = self._canv.winfo_width() 39 | self._startx = 0 40 | self._barwidth = self._maximum / self._bardiv 41 | if self._barwidth < 2: 42 | self._barwidth = 2 43 | stopx = self._startx + self._barwidth 44 | if stopx > self._maximum: 45 | stopx = self._maximum 46 | self._canv.coords(self._rect, 0, 0, stopx, self._canv.winfo_height()) 47 | self._canv.update_idletasks() 48 | 49 | def _set(self): 50 | if self._startx < 0: 51 | self._startx = 0 52 | if self._startx > self._maximum: 53 | self._startx = self._startx % self._maximum 54 | stopx = self._startx + self._barwidth 55 | if stopx > self._maximum: 56 | stopx = self._maximum 57 | self._canv.coords(self._rect, self._startx, 0, stopx, self._canv.winfo_height()) 58 | self._canv.update_idletasks() 59 | 60 | def start(self): 61 | self._running = True 62 | self.after(self._interval, self._step) 63 | 64 | def stop(self): 65 | self._running = False 66 | self._set() 67 | 68 | def _step(self): 69 | if self._running: 70 | stepsize = self._barwidth / 4 71 | if stepsize < 2: 72 | stepsize = 2 73 | self._startx += stepsize 74 | self._set() 75 | self.after(self._interval, self._step) 76 | -------------------------------------------------------------------------------- /contrib/Obok_calibre_plugin/obok_plugin_ReadMe.txt: -------------------------------------------------------------------------------- 1 | obok_plugin.zip 2 | ================ 3 | 4 | This plugin will remove the DRM from Kobo ebooks download on Mac or Windows using the Kobo desktop application, or from Kobo ebooks on an attached E-Ink Kobo reader (but not a Kobo Arc or Kobo Vox). If both are available, ebooks will be read from the attached E-Ink Kobo reader. To import from the desktop application, unplug the Kobo reader. 5 | 6 | 7 | Installation 8 | ------------ 9 | Open calibre's Preferences dialog. Click on the "Plugins" button. Next, click on the button, "Load plugin from file". Navigate to the unzipped DeDRM_tools folder and, in the folder "obok_calibre_plugin", find the file "obok_plugin.zip". Click to select the file and select "Open". Click "Yes" in the "Are you sure?" dialog box. Click the "OK" button in the "Success" dialog box. 10 | 11 | 12 | Customization 13 | ------------- 14 | No customization is required, except choosing which menus will show the plugin. Altough the ability to enter a device serial number is given, this should not need to be filled in, as the serial number should be picked up automatically from the attached Kobo reader. 15 | 16 | 17 | Using the plugin 18 | ---------------- 19 | 20 | Select the plugin's menu or icon from whichever part of the calibre interface you have chosen to have it. Follow the instructions in the dialog that appears. 21 | 22 | 23 | Troubleshooting 24 | --------------- 25 | If you find that it's not working for you (imported ebooks still have DRM - that is, they won't convert or open in the calibre ebook viewer), you should make a log of import process by deleting the DRMed ebook from calibre and then adding the ebook to calibre when it's running in debug mode. This will generate a lot of helpful debugging info that can be copied into any online help requests. Here's how to do it: 26 | 27 | On Windows, open a terminal/command window. (Start/Run… and then type 'cmd.exe' (without the 's) as the program to run). 28 | On Macintosh, open the Terminal application (in your Utilities folder). 29 | On Linux open a command window. Hopefully all Linux users know how to do this. 30 | 31 | You should now have a text-based command-line window open. 32 | 33 | Type in "calibre-debug -g" (without the "s but with the space before the -g) and press the return/enter key. Calibre will launch and run as normal, but with debugging information output to the terminal window. 34 | 35 | Import the DRMed eBook into calibre in any of the the normal ways. (I usually drag&drop onto the calibre window.) 36 | 37 | Debug information will be written to the terminal window. 38 | 39 | Copy the output from the terminal window. 40 | On Windows, you must use the window menu (little icon at left of window bar) to select all the text and then to copy it. 41 | On Macintosh and Linux, just use the normal text select and copy commands. 42 | 43 | Paste the information into a comment at my blog, http://apprenticealf.wordpress.com/ describing your problem. 44 | 45 | 46 | Credits 47 | ------- 48 | The original obok script was by Physisticated 49 | The plugin conversion was done anonymously. 50 | The Kobo reader support was added by norbusan 51 | 52 | Additional improvements to the script and the plugin adaption by numerous anonymous people. 53 | 54 | -------------------------------------------------------------------------------- /dedrm_src/simpleprefs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab 3 | 4 | import sys 5 | import os, os.path 6 | import shutil 7 | 8 | class SimplePrefsError(Exception): 9 | pass 10 | 11 | class SimplePrefs(object): 12 | def __init__(self, target, description): 13 | self.prefs = {} 14 | self.key2file={} 15 | self.file2key={} 16 | for keyfilemap in description: 17 | [key, filename] = keyfilemap 18 | self.key2file[key] = filename 19 | self.file2key[filename] = key 20 | self.target = target + 'Prefs' 21 | if sys.platform.startswith('win'): 22 | import _winreg as winreg 23 | regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\\") 24 | path = winreg.QueryValueEx(regkey, 'Local AppData')[0] 25 | prefdir = path + os.sep + self.target 26 | elif sys.platform.startswith('darwin'): 27 | home = os.getenv('HOME') 28 | prefdir = os.path.join(home,'Library','Preferences','org.' + self.target) 29 | else: 30 | # linux and various flavors of unix 31 | home = os.getenv('HOME') 32 | prefdir = os.path.join(home,'.' + self.target) 33 | if not os.path.exists(prefdir): 34 | os.makedirs(prefdir) 35 | self.prefdir = prefdir 36 | self.prefs['dir'] = self.prefdir 37 | self._loadPreferences() 38 | 39 | def _loadPreferences(self): 40 | filenames = os.listdir(self.prefdir) 41 | for filename in filenames: 42 | if filename in self.file2key: 43 | key = self.file2key[filename] 44 | filepath = os.path.join(self.prefdir,filename) 45 | if os.path.isfile(filepath): 46 | try : 47 | data = file(filepath,'rb').read() 48 | self.prefs[key] = data 49 | except Exception, e: 50 | pass 51 | 52 | def getPreferences(self): 53 | return self.prefs 54 | 55 | def setPreferences(self, newprefs={}): 56 | if 'dir' not in newprefs: 57 | raise SimplePrefsError('Error: Attempt to Set Preferences in unspecified directory') 58 | if newprefs['dir'] != self.prefs['dir']: 59 | raise SimplePrefsError('Error: Attempt to Set Preferences in unspecified directory') 60 | for key in newprefs: 61 | if key != 'dir': 62 | if key in self.key2file: 63 | filename = self.key2file[key] 64 | filepath = os.path.join(self.prefdir,filename) 65 | data = newprefs[key] 66 | if data != None: 67 | data = str(data) 68 | if data == None or data == '': 69 | if os.path.exists(filepath): 70 | os.remove(filepath) 71 | else: 72 | try: 73 | file(filepath,'wb').write(data) 74 | except Exception, e: 75 | pass 76 | self.prefs = newprefs 77 | return 78 | -------------------------------------------------------------------------------- /contrib/Other_Tools/Kindle_for_Android_Patches/kindle_version_3.0.1.70/ReadMe_K4Android.txt: -------------------------------------------------------------------------------- 1 | Kindle for Android 2 | ------------------ 3 | 4 | Kindle for Android uses a different scheme to generate its books specific PIDs than Kindle for PC, Kindle for iPhone/iPad, and standalone Kindles. 5 | 6 | Unfortunately, K4Android uses an "account secrets" file that would only be available if the device were jail-broken and even then someone would have to figure out how to decode this secret information in order to reverse the process. 7 | 8 | Instead of trying to calculate the correct PIDs for each book from this primary data, "Me" (a commenter who posted to the ApprenticeAlf site) came up with a wonderful idea to simply modify the Kindle 3 for Android application to store the PIDs it uses to decode each book in its "about activity" window. This list of PIDS can then be provided to MobiDeDRM.py, which in its latest incarnations allows a comma separated list of pids to be passed in, to successfully remove the DRM from that book. Effectively "Me" has created an "Unswindle" for the Kindle for Android 3 application! 9 | 10 | Obviously, to use "Me"'s approach, requires an Android Developer's Certificate (to sign the modified application) and access to and knowledge of the developer tools, but does not require anything to be jail-broken. 11 | 12 | This is a copy the detailed instructions supplied by "Me" to the ApprenticeAlf blog in the comments. The kindle3.patch described below is included in this folder in the tools: 13 | 14 | From the ApprenticeAlf Comments: 15 | 16 | "Me" writes: 17 | 18 | A better solution seems to create a patched version of the Kindle apk which either logs or displays it’s PID. I created a patch to both log the pid list and show it in the Kindle application in the about activity screen. The pid list isn’t available until the DRMed book has been opened (and the list seem to differ for different books). 19 | 20 | To create the patched kindle apk a certificate must be created (http://developer.android.com/guide/publishing/app-signing.html#cert) and the apktool must be build from source (all subprojects) as long as version 1.4.2 isn’t released (http://code.google.com/p/android-apktool/wiki/BuildApktool). 21 | 22 | These are the steps to pull the original apk from the Android device, uninstall it, create a patched apk and install that (tested on a rooted device, but I think all steps should also work on non-rooted devices): 23 | 24 | adb pull /data/app/com.amazon.kindle-1.apk kindle3.apk 25 | adb uninstall com.amazon.kindle 26 | apktool d kindle3.apk kindle3 27 | cd kindle3 28 | patch -p1 < ../kindle3.patch 29 | cd .. 30 | apktool b kindle3 kindle3_patched.apk 31 | jarsigner -verbose -keystore kindle.keystore kindle3_patched.apk kindle 32 | zipalign -v 4 kindle3_patched.apk kindle3_signed.apk 33 | adb install kindle3_signed.apk 34 | 35 | kindle3.patch (based on kindle version 3.0.1.70) is available on pastebin: 36 | http://pastebin.com/LNpgkcpP 37 | 38 | Have fun! 39 | 40 | Comment by me — June 9, 2011 @ 9:01 pm | Reply 41 | 42 | Hi me, 43 | Wow! Great work!!!! 44 | 45 | With your patch, you have created the equivalent of Unswindle for the Kindle for Android app and it does not even require jailbreaking! 46 | 47 | Very nice work indeed! 48 | 49 | Comment by some_updates — June 10, 2011 @ 4:28 am | Reply 50 | 51 | -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleAllowMixedLocalizations 6 | 7 | CFBundleDevelopmentRegion 8 | English 9 | CFBundleDocumentTypes 10 | 11 | 12 | CFBundleTypeExtensions 13 | 14 | * 15 | 16 | CFBundleTypeOSTypes 17 | 18 | **** 19 | 20 | CFBundleTypeRole 21 | Viewer 22 | 23 | 24 | CFBundleExecutable 25 | droplet 26 | CFBundleIconFile 27 | DeDRM 28 | CFBundleIdentifier 29 | com.apple.ScriptEditor.id.DeDRM 30 | CFBundleInfoDictionaryVersion 31 | 6.0 32 | CFBundleName 33 | DeDRM 34 | CFBundlePackageType 35 | APPL 36 | CFBundleShortVersionString 37 | 6.6.3 38 | CFBundleSignature 39 | dplt 40 | LSMinimumSystemVersionByArchitecture 41 | 42 | x86_64 43 | 10.6 44 | 45 | LSRequiresCarbon 46 | 47 | NSAppleEventsUsageDescription 48 | This script needs to control other applications to run. 49 | NSAppleMusicUsageDescription 50 | This script needs access to your music to run. 51 | NSCalendarsUsageDescription 52 | This script needs access to your calendars to run. 53 | NSCameraUsageDescription 54 | This script needs access to your camera to run. 55 | NSContactsUsageDescription 56 | This script needs access to your contacts to run. 57 | NSHomeKitUsageDescription 58 | This script needs access to your HomeKit Home to run. 59 | NSHumanReadableCopyright 60 | Copyright © 2010–2019 Apprentice Alf 61 | NSMicrophoneUsageDescription 62 | This script needs access to your microphone to run. 63 | NSPhotoLibraryUsageDescription 64 | This script needs access to your photos to run. 65 | NSRemindersUsageDescription 66 | This script needs access to your reminders to run. 67 | NSSiriUsageDescription 68 | This script needs access to Siri to run. 69 | NSSystemAdministrationUsageDescription 70 | This script needs access to administer this system to run. 71 | WindowState 72 | 73 | bundleDividerCollapsed 74 | 75 | bundlePositionOfDivider 76 | 1162 77 | dividerCollapsed 78 | 79 | eventLogLevel 80 | 0 81 | name 82 | ScriptWindowState 83 | positionOfDivider 84 | 651 85 | savedFrame 86 | 0 37 1680 990 0 0 1680 1027 87 | selectedTab 88 | log 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /dedrm_src/openssl_des.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab 3 | 4 | # implement just enough of des from openssl to make erdr2pml.py happy 5 | 6 | def load_libcrypto(): 7 | from ctypes import CDLL, POINTER, c_void_p, c_char_p, c_char, c_int, c_long, \ 8 | Structure, c_ulong, create_string_buffer, cast 9 | from ctypes.util import find_library 10 | import sys 11 | 12 | if sys.platform.startswith('win'): 13 | libcrypto = find_library('libeay32') 14 | else: 15 | libcrypto = find_library('crypto') 16 | 17 | if libcrypto is None: 18 | return None 19 | 20 | libcrypto = CDLL(libcrypto) 21 | 22 | # typedef struct DES_ks 23 | # { 24 | # union 25 | # { 26 | # DES_cblock cblock; 27 | # /* make sure things are correct size on machines with 28 | # * 8 byte longs */ 29 | # DES_LONG deslong[2]; 30 | # } ks[16]; 31 | # } DES_key_schedule; 32 | 33 | # just create a big enough place to hold everything 34 | # it will have alignment of structure so we should be okay (16 byte aligned?) 35 | class DES_KEY_SCHEDULE(Structure): 36 | _fields_ = [('DES_cblock1', c_char * 16), 37 | ('DES_cblock2', c_char * 16), 38 | ('DES_cblock3', c_char * 16), 39 | ('DES_cblock4', c_char * 16), 40 | ('DES_cblock5', c_char * 16), 41 | ('DES_cblock6', c_char * 16), 42 | ('DES_cblock7', c_char * 16), 43 | ('DES_cblock8', c_char * 16), 44 | ('DES_cblock9', c_char * 16), 45 | ('DES_cblock10', c_char * 16), 46 | ('DES_cblock11', c_char * 16), 47 | ('DES_cblock12', c_char * 16), 48 | ('DES_cblock13', c_char * 16), 49 | ('DES_cblock14', c_char * 16), 50 | ('DES_cblock15', c_char * 16), 51 | ('DES_cblock16', c_char * 16)] 52 | 53 | DES_KEY_SCHEDULE_p = POINTER(DES_KEY_SCHEDULE) 54 | 55 | def F(restype, name, argtypes): 56 | func = getattr(libcrypto, name) 57 | func.restype = restype 58 | func.argtypes = argtypes 59 | return func 60 | 61 | DES_set_key = F(None, 'DES_set_key',[c_char_p, DES_KEY_SCHEDULE_p]) 62 | DES_ecb_encrypt = F(None, 'DES_ecb_encrypt',[c_char_p, c_char_p, DES_KEY_SCHEDULE_p, c_int]) 63 | 64 | 65 | class DES(object): 66 | def __init__(self, key): 67 | if len(key) != 8 : 68 | raise Exception('DES improper key used') 69 | return 70 | self.key = key 71 | self.keyschedule = DES_KEY_SCHEDULE() 72 | DES_set_key(self.key, self.keyschedule) 73 | def desdecrypt(self, data): 74 | ob = create_string_buffer(len(data)) 75 | DES_ecb_encrypt(data, ob, self.keyschedule, 0) 76 | return ob.raw 77 | def decrypt(self, data): 78 | if not data: 79 | return '' 80 | i = 0 81 | result = [] 82 | while i < len(data): 83 | block = data[i:i+8] 84 | processed_block = self.desdecrypt(block) 85 | result.append(processed_block) 86 | i += 8 87 | return ''.join(result) 88 | 89 | return DES 90 | -------------------------------------------------------------------------------- /dedrm_src/wineutils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import with_statement 5 | 6 | __license__ = 'GPL v3' 7 | 8 | # Standard Python modules. 9 | import os, sys, re, hashlib 10 | from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION 11 | 12 | def WineGetKeys(scriptpath, extension, wineprefix=""): 13 | import subprocess 14 | from subprocess import Popen, PIPE, STDOUT 15 | 16 | import subasyncio 17 | from subasyncio import Process 18 | 19 | if extension == u".k4i": 20 | import json 21 | 22 | basepath, script = os.path.split(scriptpath) 23 | print u"{0} v{1}: Running {2} under Wine".format(PLUGIN_NAME, PLUGIN_VERSION, script) 24 | 25 | outdirpath = os.path.join(basepath, u"winekeysdir") 26 | if not os.path.exists(outdirpath): 27 | os.makedirs(outdirpath) 28 | 29 | wineprefix = os.path.abspath(os.path.expanduser(os.path.expandvars(wineprefix))) 30 | if wineprefix != "" and os.path.exists(wineprefix): 31 | cmdline = u"WINEPREFIX=\"{2}\" wine python.exe \"{0}\" \"{1}\"".format(scriptpath,outdirpath,wineprefix) 32 | else: 33 | cmdline = u"wine python.exe \"{0}\" \"{1}\"".format(scriptpath,outdirpath) 34 | print u"{0} v{1}: Command line: '{2}'".format(PLUGIN_NAME, PLUGIN_VERSION, cmdline) 35 | 36 | try: 37 | cmdline = cmdline.encode(sys.getfilesystemencoding()) 38 | p2 = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=sys.stdout, stderr=STDOUT, close_fds=False) 39 | result = p2.wait("wait") 40 | except Exception, e: 41 | print u"{0} v{1}: Wine subprocess call error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0]) 42 | if wineprefix != "" and os.path.exists(wineprefix): 43 | cmdline = u"WINEPREFIX=\"{2}\" wine C:\\Python27\\python.exe \"{0}\" \"{1}\"".format(scriptpath,outdirpath,wineprefix) 44 | else: 45 | cmdline = u"wine C:\\Python27\\python.exe \"{0}\" \"{1}\"".format(scriptpath,outdirpath) 46 | print u"{0} v{1}: Command line: “{2}”".format(PLUGIN_NAME, PLUGIN_VERSION, cmdline) 47 | 48 | try: 49 | cmdline = cmdline.encode(sys.getfilesystemencoding()) 50 | p2 = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=sys.stdout, stderr=STDOUT, close_fds=False) 51 | result = p2.wait("wait") 52 | except Exception, e: 53 | print u"{0} v{1}: Wine subprocess call error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0]) 54 | 55 | # try finding winekeys anyway, even if above code errored 56 | winekeys = [] 57 | # get any files with extension in the output dir 58 | files = [f for f in os.listdir(outdirpath) if f.endswith(extension)] 59 | for filename in files: 60 | try: 61 | fpath = os.path.join(outdirpath, filename) 62 | with open(fpath, 'rb') as keyfile: 63 | if extension == u".k4i": 64 | new_key_value = json.loads(keyfile.read()) 65 | else: 66 | new_key_value = keyfile.read() 67 | winekeys.append(new_key_value) 68 | except: 69 | print u"{0} v{1}: Error loading file {2}".format(PLUGIN_NAME, PLUGIN_VERSION, filename) 70 | traceback.print_exc() 71 | os.remove(fpath) 72 | print u"{0} v{1}: Found and decrypted {2} {3}".format(PLUGIN_NAME, PLUGIN_VERSION, len(winekeys), u"key file" if len(winekeys) == 1 else u"key files") 73 | return winekeys 74 | -------------------------------------------------------------------------------- /dedrm_src/DeDRM_Kindle for Mac and PC Key_Help.htm: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | Managing Kindle for Mac/PC Keys 9 | 16 | 17 | 18 | 19 | 20 |

Managing Kindle for Mac/PC Keys

21 | 22 | 23 |

If you have upgraded from an earlier version of the plugin, any existing Kindle for Mac/PC keys will have been automatically imported, so you might not need to do any more configuration. In addition, on Windows and Mac, the default Kindle for Mac/PC key is added the first time the plugin is run. Continue reading for key generation and management instructions.

24 | 25 |

Creating New Keys:

26 | 27 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog prompting you to enter a key name for the default Kindle for Mac/PC key.

28 |
    29 |
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys.
  • 30 |
31 | 32 |

Click the OK button to create and store the Kindle for Mac/PC key for the current installation of Kindle for Mac/PC. Or Cancel if you don’t want to create the key.

33 |

New keys are checked against the current list of keys before being added, and duplicates are discarded.

34 | 35 |

Deleting Keys:

36 | 37 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

38 | 39 |

Renaming Keys:

40 | 41 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

42 | 43 |

Exporting Keys:

44 | 45 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.der’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

46 | 47 |

Linux Users: WINEPREFIX

48 | 49 |

Under the list of keys, Linux users will see a text field labeled "WINEPREFIX". If you are use Kindle for PC under Wine, and your wine installation containing Kindle for PC isn't the default Wine installation, you may enter the full path to the correct Wine installation here. Leave blank if you are unsure.

50 | 51 |

Importing Existing Keyfiles:

52 | 53 |

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.k4i’ key files. Key files might come from being exported from this plugin, or may have been generated using the kindlekey.pyw script running under Wine on Linux systems.

54 | 55 |

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dedrm_src/DeDRM_eReader Key_Help.htm: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | Managing eReader Keys 9 | 16 | 17 | 18 | 19 | 20 |

Managing eReader Keys

21 | 22 |

If you have upgraded from an earlier version of the plugin, any existing eReader (Fictionwise ‘.pdb’) keys will have been automatically imported, so you might not need to do any more configuration. Continue reading for key generation and management instructions.

23 | 24 |

Creating New Keys:

25 | 26 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering the necessary data to generate a new key.

27 |
    28 |
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys. Choose something that will help you remember the data (name, cc#) it was created with.
  • 29 |
  • Your Name: This is the name used by Fictionwise to generate your encryption key. Since Fictionwise has now closed down, you might not have easy access to this. It was often the name on the Credit Card used at Fictionwise.
  • 30 |
  • Credit Card#: this is the default credit card number that was on file with Fictionwise at the time of download of the ebook to be de-DRMed. Just enter the last 8 digits of the number. As with the name, this number will not be stored anywhere on your computer or in calibre. It will only be used in the creation of the one-way hash/key that’s stored in the preferences.
  • 31 |
32 | 33 |

Click the OK button to create and store the generated key. Or Cancel if you don’t want to create a key.

34 |

New keys are checked against the current list of keys before being added, and duplicates are discarded.

35 | 36 |

Deleting Keys:

37 | 38 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

39 | 40 |

Renaming Keys:

41 | 42 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

43 | 44 |

Exporting Keys:

45 | 46 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.b63’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

47 | 48 |

Importing Existing Keyfiles:

49 | 50 |

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.b63’ key files that have previously been exported.

51 | 52 |

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /dedrm_src/DeDRM_Adobe Digital Editions Key_Help.htm: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | Managing Adobe Digital Editions Keys 9 | 16 | 17 | 18 | 19 | 20 |

Managing Adobe Digital Editions Keys

21 | 22 | 23 |

If you have upgraded from an earlier version of the plugin, any existing Adobe Digital Editions keys will have been automatically imported, so you might not need to do any more configuration. In addition, on Windows and Mac, the default Adobe Digital Editions key is added the first time the plugin is run. Continue reading for key generation and management instructions.

24 | 25 |

Creating New Keys:

26 | 27 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog prompting you to enter a key name for the default Adobe Digital Editions key.

28 |
    29 |
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys.
  • 30 |
31 | 32 |

Click the OK button to create and store the Adobe Digital Editions key for the current installation of Adobe Digital Editions. Or Cancel if you don’t want to create the key.

33 |

New keys are checked against the current list of keys before being added, and duplicates are discarded.

34 | 35 |

Deleting Keys:

36 | 37 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

38 | 39 |

Renaming Keys:

40 | 41 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

42 | 43 |

Exporting Keys:

44 | 45 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.der’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

46 | 47 |

Linux Users: WINEPREFIX

48 | 49 |

Under the list of keys, Linux users will see a text field labeled "WINEPREFIX". If you are use Adobe Digital Editions under Wine, and your wine installation containing Adobe Digital Editions isn't the default Wine installation, you may enter the full path to the correct Wine installation here. Leave blank if you are unsure.

50 | 51 |

Importing Existing Keyfiles:

52 | 53 |

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.der’ key files. Key files might come from being exported from this or older plugins, or may have been generated using the adobekey.pyw script running under Wine on Linux systems.

54 | 55 |

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes will only be saved permanently when you click OK in the main configuration dialog.

56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /dedrm_src/kfxdedrm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import with_statement 5 | 6 | # Engine to remove drm from Kindle KFX ebooks 7 | 8 | import os 9 | import shutil 10 | import zipfile 11 | 12 | try: 13 | from cStringIO import StringIO 14 | except ImportError: 15 | from StringIO import StringIO 16 | 17 | try: 18 | from calibre_plugins.dedrm import ion 19 | except ImportError: 20 | import ion 21 | 22 | 23 | __license__ = 'GPL v3' 24 | __version__ = '1.0' 25 | 26 | 27 | class KFXZipBook: 28 | def __init__(self, infile): 29 | self.infile = infile 30 | self.voucher = None 31 | self.decrypted = {} 32 | 33 | def getPIDMetaInfo(self): 34 | return (None, None) 35 | 36 | def processBook(self, totalpids): 37 | with zipfile.ZipFile(self.infile, 'r') as zf: 38 | for filename in zf.namelist(): 39 | with zf.open(filename) as fh: 40 | data = fh.read(8) 41 | if data != '\xeaDRMION\xee': 42 | continue 43 | data += fh.read() 44 | if self.voucher is None: 45 | self.decrypt_voucher(totalpids) 46 | print u'Decrypting KFX DRMION: {0}'.format(filename) 47 | outfile = StringIO() 48 | ion.DrmIon(StringIO(data[8:-8]), lambda name: self.voucher).parse(outfile) 49 | self.decrypted[filename] = outfile.getvalue() 50 | 51 | if not self.decrypted: 52 | print(u'The .kfx-zip archive does not contain an encrypted DRMION file') 53 | 54 | def decrypt_voucher(self, totalpids): 55 | with zipfile.ZipFile(self.infile, 'r') as zf: 56 | for info in zf.infolist(): 57 | with zf.open(info.filename) as fh: 58 | data = fh.read(4) 59 | if data != '\xe0\x01\x00\xea': 60 | continue 61 | 62 | data += fh.read() 63 | if 'ProtectedData' in data: 64 | break # found DRM voucher 65 | else: 66 | raise Exception(u'The .kfx-zip archive contains an encrypted DRMION file without a DRM voucher') 67 | 68 | print u'Decrypting KFX DRM voucher: {0}'.format(info.filename) 69 | 70 | for pid in [''] + totalpids: 71 | for dsn_len,secret_len in [(0,0), (16,0), (16,40), (32,40), (40,40)]: 72 | if len(pid) == dsn_len + secret_len: 73 | break # split pid into DSN and account secret 74 | else: 75 | continue 76 | 77 | try: 78 | voucher = ion.DrmIonVoucher(StringIO(data), pid[:dsn_len], pid[dsn_len:]) 79 | voucher.parse() 80 | voucher.decryptvoucher() 81 | break 82 | except: 83 | pass 84 | else: 85 | raise Exception(u'Failed to decrypt KFX DRM voucher with any key') 86 | 87 | print u'KFX DRM voucher successfully decrypted' 88 | 89 | license_type = voucher.getlicensetype() 90 | if license_type != "Purchase": 91 | raise Exception((u'This book is licensed as {0}. ' 92 | 'These tools are intended for use on purchased books.').format(license_type)) 93 | 94 | self.voucher = voucher 95 | 96 | def getBookTitle(self): 97 | return os.path.splitext(os.path.split(self.infile)[1])[0] 98 | 99 | def getBookExtension(self): 100 | return '.kfx-zip' 101 | 102 | def getBookType(self): 103 | return 'KFX-ZIP' 104 | 105 | def cleanup(self): 106 | pass 107 | 108 | def getFile(self, outpath): 109 | if not self.decrypted: 110 | shutil.copyfile(self.infile, outpath) 111 | else: 112 | with zipfile.ZipFile(self.infile, 'r') as zif: 113 | with zipfile.ZipFile(outpath, 'w') as zof: 114 | for info in zif.infolist(): 115 | zof.writestr(info, self.decrypted.get(info.filename, zif.read(info.filename))) 116 | -------------------------------------------------------------------------------- /dedrm_src/DeDRM_Kindle for Android Key_Help.htm: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | Managing Kindle for Android Keys 9 | 16 | 17 | 18 | 19 | 20 |

Managing Kindle for Android Keys

21 | 22 |

Amazon's Kindle for Android application uses an internal key equivalent to an eInk Kindle's serial number. Extracting that key is a little tricky, but worth it, as it then allows the DRM to be removed from any Kindle ebooks that have been downloaded to that Android device.

23 | 24 |

Please note that it is not currently known whether the same applies to the Kindle application on the Kindle Fire and Fire HD.

25 | 26 |

Getting the Kindle for Android backup file

27 | 28 |

Obtain and install adb (Android Debug Bridge) on your computer. Details of how to do this are beyond the scope of this help file, but there are plenty of on-line guides.

29 |

Enable developer mode on your Android device. Again, look for an on-line guide for your device.

30 |

Once you have adb installed and your device in developer mode, connect your device to your computer with a USB cable and then open up a command line (Terminal on Mac OS X and cmd.exe on Windows) and enter "adb backup com.amazon.kindle" (without the quotation marks!) and press return. A file "backup.ab" should be created in your home directory. 31 | 32 |

Adding a Kindle for Android Key

33 | 34 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog with two main controls. 35 |

    36 |
  • Choose backup file: click this button and you will be prompted to find the backup.ab file you created earlier. Once selected the file will be processed to extract the decryption key, and if successful the file name will be displayed to the right of the button.
  • 37 |
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of Kindle for Android keys. Enter a name that will help you remember which device this key came from.
  • 38 |
39 | 40 |

Click the OK button to store the Kindle for Android key for the current list of Kindle for Android keys. Or click Cancel if you don’t want to store the key.

41 |

New keys are checked against the current list of keys before being added, and duplicates are discarded.

42 | 43 |

Deleting Keys:

44 | 45 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

46 | 47 |

Renaming Keys:

48 | 49 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will prompt you to enter a new name for the highlighted key in the list. Enter the new name for the key and click the OK button to use the new name, or Cancel to revert to the old name.

50 | 51 |

Exporting Keys:

52 | 53 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.k4a' file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

54 | 55 |

Importing Existing Keyfiles:

56 | 57 |

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import any ‘.k4a’ file you obtained by using the androidkindlekey.py script manually, or by exporting from another copy of calibre.

58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /contrib/DeDRM_Windows_Application/DeDRM_App_ReadMe.txt: -------------------------------------------------------------------------------- 1 | DeDRM_App - DeDRM_App.pyw and DeDRM_Drop_Target.bat 2 | =================================================== 3 | 4 | DeDRM_App.pyw is a python drag and drop application that allows users to drag and drop ebooks or folders of ebooks onto the DeDRM_Drop_Target.bat to have the DRM removed. It repackages all the tools (except obok) in one easy to use program that remembers preferences and settings. 5 | 6 | It will work without manual configuration for Kindle for PC ebooks, Adobe Digital Edition (2.0.1) epub and pdf ebooks and Barnes & Noble NOOK Study ePubs when Kindle for PC, Adobe Digital Editions and NOOK Study are installed on the same computer and user account. 7 | 8 | To remove the DRM from eInk Kindle ebooks, Mobipocket ebooks and Fictionwise eReader ebooks requires the user to double-click the DeDRM_Drop_Target.bat file and set some additional Preferences including: 9 | 10 | eInk Kindle: 16 digit Serial Number 11 | MobiPocket: 10 digit PID 12 | eReader Social DRM: Name:Last 8 digits of CC number 13 | 14 | Once these preferences have been set, the user can simply drag and drop ebooks onto the DeDRM_Drop_Target to remove the DRM. Note that after setting preferences it is necessary to click on "Set Prefs" button and then quit the application for the change in preferences to fully take effect. 15 | 16 | This program requires that Python 2.7 and PyCrypto 2.6 for Python 2.7 be installed on your computer before it will work. See below for how to get and install these programs for Windows. 17 | 18 | 19 | Installation 20 | ------------ 21 | 0. If you don't already have a correct version of Python and PyCrypto installed, follow the "Installing Python on Windows" and "Installing PyCrypto on Windows" sections below before continuing. 22 | 23 | 1. Drag the DeDRM_App folder from DeDRM_Application_Windows to your "My Documents" folder. 24 | 25 | 2. Open the DeDRM_App folder you've just dragged, and make a short-cut of the DeDRM_Drop_Target.bat file (right-click/Create Shortcut). Drag the shortcut file onto your Desktop. 26 | 27 | 3. To set the preferences simply double-click on the short-cut you've just created. 28 | 29 | 30 | Credits 31 | ------- 32 | The original inept and ignoble scripts were by i♥cabbages 33 | The original mobidedrm and erdr2pml scripts were by The Dark Reverser 34 | The original topaz DRM removal script was by CMBDTC 35 | The original topaz format conversion scripts were by some_updates, clarknova and Bart Simpson 36 | 37 | The alfcrypto library is by some_updates 38 | The ePub encryption detection script is by Apprentice Alf, adapted from a script by Paul Durrant 39 | The ignoblekey script is by Apprentice Harper 40 | The DeDRM python GUI was by some_updates and is maintained by Apprentice Alf and Apprentice Harper 41 | 42 | Many fixes, updates and enhancements to the scripts and applicatons have been made by many other people. For more details, see the commments in the individual scripts. 43 | 44 | 45 | Installing Python on Windows 46 | ---------------------------- 47 | I strongly recommend fully installing ActiveState’s Active Python, free Community Edition for Windows. This is a free, full version of the Python. It comes with some important additional modules that are not included in the bare-bones version from www.python.org unless you choose to install everything. 48 | 49 | 1. Download ActivePython 2.7.8 for Windows (or later 2.7.x version for Windows, but NOT 3.x) from http://www.activestate.com/activepython/downloads. 50 | 51 | 2. When it has finished downloading, run the installer. Accept the default options. 52 | 53 | 54 | Installing PyCrypto on Windows 55 | ------------------------------ 56 | PyCrypto is a set of encryption/decryption routines that work with Python. The sources are freely available, and compiled versions are available from several sources. You must install a version that is for Python 2.7. I recommend the installer linked from Michael Foord’s blog. 57 | 58 | 1. Download PyCrypto 2.6 (or later) for Windows and Python 2.7 from http://www.voidspace.org.uk/python/modules.shtml#pycrypto 59 | 60 | 2. When it has finished downloading, run the application. Accept the default options. 61 | 62 | 63 | Linux Users 64 | =========== 65 | The DeDRM_app.pyw script, although not the .bat shortcut, should work under Linux. Drag & drop functionality is not available. Depending on your Linux installation, you may or may not need to install Python 2 and PyCrypto. 66 | -------------------------------------------------------------------------------- /contrib/Other_Tools/Kindle_for_Android_Patches/kindle_version_3.0.1.70/kindle3.0.1.70.patch: -------------------------------------------------------------------------------- 1 | diff -ru kindle3_orig/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali kindle3/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali 2 | --- kindle3_orig/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali 3 | +++ kindle3/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali 4 | @@ -11,6 +11,8 @@ 5 | 6 | .field private security:Lcom/mobipocket/android/library/reader/AndroidSecurity; 7 | 8 | +.field private pidList:Ljava/lang/String; 9 | + 10 | 11 | # direct methods 12 | .method public constructor (Lcom/mobipocket/android/library/reader/AndroidSecurity;Lcom/amazon/kcp/application/AndroidDeviceType;)V 13 | @@ -28,6 +30,10 @@ 14 | .line 26 15 | iput-object p2, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->deviceType:Lcom/amazon/kcp/application/AndroidDeviceType; 16 | 17 | + const-string v0, "Open DRMed book to show PID list." 18 | + 19 | + iput-object v0, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String; 20 | + 21 | .line 27 22 | new-instance v0, Ljava/lang/StringBuilder; 23 | 24 | @@ -175,4 +181,26 @@ 25 | move-result-object v0 26 | 27 | return-object v0 28 | +.end method 29 | + 30 | +.method public getPidList()Ljava/lang/String; 31 | + .locals 1 32 | + 33 | + .prologue 34 | + .line 15 35 | + iget-object v0, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String; 36 | + 37 | + return-object v0 38 | +.end method 39 | + 40 | +.method public setPidList(Ljava/lang/String;)V 41 | + .locals 0 42 | + .parameter "value" 43 | + 44 | + .prologue 45 | + .line 11 46 | + iput-object p1, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String; 47 | + 48 | + .line 12 49 | + return-void 50 | .end method 51 | diff -ru kindle3_orig/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali kindle3/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali 52 | --- kindle3_orig/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali 53 | +++ kindle3/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali 54 | @@ -27,3 +27,9 @@ 55 | 56 | .method public abstract getPid()Ljava/lang/String; 57 | .end method 58 | + 59 | +.method public abstract getPidList()Ljava/lang/String; 60 | +.end method 61 | + 62 | +.method public abstract setPidList(Ljava/lang/String;)V 63 | +.end method 64 | \ No newline at end of file 65 | diff -ru kindle3_orig/smali/com/amazon/kcp/info/AboutActivity.smali kindle3/smali/com/amazon/kcp/info/AboutActivity.smali 66 | --- kindle3_orig/smali/com/amazon/kcp/info/AboutActivity.smali 67 | +++ kindle3/smali/com/amazon/kcp/info/AboutActivity.smali 68 | @@ -32,9 +32,11 @@ 69 | invoke-direct {v6, v1}, Ljava/util/ArrayList;->(I)V 70 | 71 | .line 36 72 | - const v1, 0x7f0b0005 73 | + invoke-static {}, Lcom/amazon/kcp/application/DeviceInformationProviderFactory;->getProvider()Lcom/amazon/kcp/application/IDeviceInformationProvider; 74 | 75 | - invoke-virtual {p0, v1}, Lcom/amazon/kcp/info/AboutActivity;->getString(I)Ljava/lang/String; 76 | + move-result-object v0 77 | + 78 | + invoke-interface {v0}, Lcom/amazon/kcp/application/IDeviceInformationProvider;->getPidList()Ljava/lang/String; 79 | 80 | move-result-object v1 81 | 82 | diff -ru kindle3_orig/smali/com/amazon/system/security/Security.smali kindle3/smali/com/amazon/system/security/Security.smali 83 | --- kindle3_orig/smali/com/amazon/system/security/Security.smali 84 | +++ kindle3/smali/com/amazon/system/security/Security.smali 85 | @@ -884,6 +884,15 @@ 86 | 87 | .line 332 88 | :cond_1 89 | + 90 | + const-string v1, "PID list" 91 | + invoke-static {}, Lcom/amazon/kcp/application/DeviceInformationProviderFactory;->getProvider()Lcom/amazon/kcp/application/IDeviceInformationProvider; 92 | + move-result-object v0 93 | + invoke-static {v7}, Ljava/util/Arrays;->toString([Ljava/lang/Object;)Ljava/lang/String; 94 | + move-result-object v2 95 | + invoke-interface {v0, v2}, Lcom/amazon/kcp/application/IDeviceInformationProvider;->setPidList(Ljava/lang/String;)V 96 | + invoke-static {v1, v2}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I 97 | + 98 | return-object v7 99 | 100 | :cond_2 101 | -------------------------------------------------------------------------------- /contrib/Other_Tools/Kindle_for_Android_Patches/kindle_version_3.7.0.108/ReadMe_K4Android.txt: -------------------------------------------------------------------------------- 1 | Kindle for Android 2 | ------------------ 3 | 4 | Kindle for Android uses a different scheme to generate its books specific PIDs than Kindle for PC, Kindle for iPhone/iPad, and standalone Kindles. 5 | 6 | Unfortunately, K4Android uses an "account secrets" file that would only be available if the device were jail-broken and even then someone would have to figure out how to decode this secret information in order to reverse the process. 7 | 8 | Instead of trying to calculate the correct PIDs for each book from this primary data, "Me" (a commenter who posted to the ApprenticeAlf site) came up with a wonderful idea to simply modify the Kindle 3 for Android application to store the PIDs it uses to decode each book in its "about activity" window. This list of PIDS can then be provided to MobiDeDRM.py, which in its latest incarnations allows a comma separated list of pids to be passed in, to successfully remove the DRM from that book. Effectively "Me" has created an "Unswindle" for the Kindle for Android 3 application! 9 | 10 | "Me"'s original patch was for Kindle for Android version 3.0.1.70. Now "Me II" has created a patch for Kindle for Android version 3.7.0.108 and new instructions, since some of the previous steps are no longer necessary. 11 | 12 | From the ApprenticeAlf Comments: 13 | 14 | 15 | "Me II" writes: 16 | 17 | Since “Me”‘s old method for getting PIDs from Kindle for Android is outdated and no longer works with newer versions of the app, I decided I’d take a stab at bringing it up to date. It took a little fiddling to get everything working, considering how much has changed since the last patch, but I managed to do it. The process is pretty much identical to “Me”‘s original instructions, with a few minor changes. 18 | 19 | 1) You don’t need to build apktool from source. You can just grab the binaries from here for whatever OS you’re running: http://code.google.com/p/android-apktool/ 20 | 2) When you sign the rebuilt APK, use the following command instead of the one in the instructions: 21 | jarsigner -verbose -sigalg MD5withRSA -digestalg SHA1 -keystore kindle.keystore kindle3_patched.apk kindle 22 | 3) It no longer logs the PIDs, only displays them within the app. 23 | 24 | You can get the new patch, for version 3.7.0.108, here: http://pastebin.com/6FN2cTSN 25 | 26 | And here’s a screenshot of the updated menu: http://imgur.com/BbFVF (sorry for the Japanese, I was too lazy to change my phone’s language). 27 | 28 | Subsequently, "s" wrote: 29 | 30 | For others it would be useful to add the keystore generation command into the help file: 31 | keytool -genkey -v -keystore kindle.keystore -alias kindle -keyalg RSA -keysize 2048 -validity 10000 32 | As well as location of prc’s on android being (with sdcard): 33 | /mnt/sdcard/Android/data/com.amazon.kindle/files/ 34 | 35 | "s" also reported success with using the patch on version 3.7.1.8, although I recommend using the 3.7.0.108 version just in case. 36 | 37 | 38 | "Me"'s original instructions, from the ApprenticeAlf Comments: 39 | 40 | "Me" writes: 41 | 42 | A better solution seems to create a patched version of the Kindle apk which either logs or displays it’s PID. I created a patch to both log the pid list and show it in the Kindle application in the about activity screen. The pid list isn’t available until the DRMed book has been opened (and the list seem to differ for different books). 43 | 44 | To create the patched kindle apk a certificate must be created (http://developer.android.com/guide/publishing/app-signing.html#cert) and the apktool must be build from source (all subprojects) as long as version 1.4.2 isn’t released (http://code.google.com/p/android-apktool/wiki/BuildApktool). 45 | 46 | These are the steps to pull the original apk from the Android device, uninstall it, create a patched apk and install that (tested on a rooted device, but I think all steps should also work on non-rooted devices): 47 | 48 | adb pull /data/app/com.amazon.kindle-1.apk kindle3.apk 49 | adb uninstall com.amazon.kindle 50 | apktool d kindle3.apk kindle3 51 | cd kindle3 52 | patch -p1 < ../kindle3.patch 53 | cd .. 54 | apktool b kindle3 kindle3_patched.apk 55 | jarsigner -verbose -keystore kindle.keystore kindle3_patched.apk kindle 56 | zipalign -v 4 kindle3_patched.apk kindle3_signed.apk 57 | adb install kindle3_signed.apk 58 | 59 | kindle3.patch (based on kindle version 3.0.1.70) is available on pastebin: 60 | http://pastebin.com/LNpgkcpP 61 | 62 | Have fun! 63 | 64 | Comment by me — June 9, 2011 @ 9:01 pm | Reply 65 | 66 | Hi me, 67 | Wow! Great work!!!! 68 | 69 | With your patch, you have created the equivalent of Unswindle for the Kindle for Android app and it does not even require jailbreaking! 70 | 71 | Very nice work indeed! 72 | 73 | Comment by some_updates — June 10, 2011 @ 4:28 am | Reply 74 | 75 | -------------------------------------------------------------------------------- /dedrm_src/DeDRM_Barnes and Noble Key_Help.htm: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | Managing Barnes and Noble Keys 9 | 16 | 17 | 18 | 19 | 20 |

Managing Barnes and Noble Keys

21 | 22 | 23 |

If you have upgraded from an earlier version of the plugin, any existing Barnes and Noble keys will have been automatically imported, so you might not need to do any more configuration. Continue reading for key generation and management instructions.

24 | 25 |

Changes at Barnes & Noble

26 | 27 |

In mid-2014, Barnes & Noble changed the way they generated encryption keys. Instead of deriving the key from the user's name and credit card number, they started generating a random key themselves, sending that key through to devices when they connected to the Barnes & Noble servers. This means that most users will now find that no combination of their name and CC# will work in decrypting their recently downloaded ebooks.

28 | 29 |

Someone commenting at Apprentice Alf's blog detailed a way to retrieve a new account key using the account's email address and password. This method has now been incorporated into the plugin. 30 | 31 |

Creating New Keys:

32 | 33 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering the necessary data to generate a new key.

34 |
    35 |
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys. Choose something that will help you remember the data (account email address) it was created with.
  • 36 |
  • B&N/nook account email address: This is the default email address for your Barnes and Noble/nook account. This email will not be stored anywhere on your computer or in calibre. It will only be used to fetch the account key that from the B&N server, and it is that key that will be stored in the preferences.
  • 37 |
  • B&N/nook account password: this is the password for your Barnes and Noble/nook account. As with the email address, this will not be stored anywhere on your computer or in calibre. It will only be used to fetch the key from the B&N server.
  • 38 |
39 | 40 |

Click the OK button to create and store the generated key. Or Cancel if you don’t want to create a key.

41 |

New keys are checked against the current list of keys before being added, and duplicates are discarded.

42 | 43 |

Deleting Keys:

44 | 45 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

46 | 47 |

Renaming Keys:

48 | 49 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

50 | 51 |

Exporting Keys:

52 | 53 |

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.b64’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

54 | 55 |

Importing Existing Keyfiles:

56 | 57 |

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.b64’ key files. Key files might come from being exported from this or older plugins, or may have been generated using the original i♥cabbages script, or you may have made it by following the instructions above.

58 | 59 |

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

60 | 61 |

NOOK Study

62 |

Books downloaded through NOOK Study may or may not use the key found using the above method. If a book is not decrypted successfully with any of the keys, the plugin will attempt to recover keys from the NOOK Study log file and use them.

63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /dedrm_src/kindlepid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Mobipocket PID calculator v0.4 for Amazon Kindle. 5 | # Copyright (c) 2007, 2009 Igor Skochinsky 6 | # History: 7 | # 0.1 Initial release 8 | # 0.2 Added support for generating PID for iPhone (thanks to mbp) 9 | # 0.3 changed to autoflush stdout, fixed return code usage 10 | # 0.3 updated for unicode 11 | # 0.4 Added support for serial numbers starting with '9', fixed unicode bugs. 12 | # 0.5 moved unicode_argv call inside main for Windows DeDRM compatibility 13 | 14 | import sys 15 | import binascii 16 | 17 | # Wrap a stream so that output gets flushed immediately 18 | # and also make sure that any unicode strings get 19 | # encoded using "replace" before writing them. 20 | class SafeUnbuffered: 21 | def __init__(self, stream): 22 | self.stream = stream 23 | self.encoding = stream.encoding 24 | if self.encoding == None: 25 | self.encoding = "utf-8" 26 | def write(self, data): 27 | if isinstance(data,unicode): 28 | data = data.encode(self.encoding,"replace") 29 | self.stream.write(data) 30 | self.stream.flush() 31 | def __getattr__(self, attr): 32 | return getattr(self.stream, attr) 33 | 34 | iswindows = sys.platform.startswith('win') 35 | isosx = sys.platform.startswith('darwin') 36 | 37 | def unicode_argv(): 38 | if iswindows: 39 | # Uses shell32.GetCommandLineArgvW to get sys.argv as a list of Unicode 40 | # strings. 41 | 42 | # Versions 2.x of Python don't support Unicode in sys.argv on 43 | # Windows, with the underlying Windows API instead replacing multi-byte 44 | # characters with '?'. 45 | 46 | 47 | from ctypes import POINTER, byref, cdll, c_int, windll 48 | from ctypes.wintypes import LPCWSTR, LPWSTR 49 | 50 | GetCommandLineW = cdll.kernel32.GetCommandLineW 51 | GetCommandLineW.argtypes = [] 52 | GetCommandLineW.restype = LPCWSTR 53 | 54 | CommandLineToArgvW = windll.shell32.CommandLineToArgvW 55 | CommandLineToArgvW.argtypes = [LPCWSTR, POINTER(c_int)] 56 | CommandLineToArgvW.restype = POINTER(LPWSTR) 57 | 58 | cmd = GetCommandLineW() 59 | argc = c_int(0) 60 | argv = CommandLineToArgvW(cmd, byref(argc)) 61 | if argc.value > 0: 62 | # Remove Python executable and commands if present 63 | start = argc.value - len(sys.argv) 64 | return [argv[i] for i in 65 | xrange(start, argc.value)] 66 | # if we don't have any arguments at all, just pass back script name 67 | # this should never happen 68 | return [u"kindlepid.py"] 69 | else: 70 | argvencoding = sys.stdin.encoding 71 | if argvencoding == None: 72 | argvencoding = "utf-8" 73 | return [arg if (type(arg) == unicode) else unicode(arg,argvencoding) for arg in sys.argv] 74 | 75 | if sys.hexversion >= 0x3000000: 76 | print 'This script is incompatible with Python 3.x. Please install Python 2.7.x.' 77 | sys.exit(2) 78 | 79 | letters = 'ABCDEFGHIJKLMNPQRSTUVWXYZ123456789' 80 | 81 | def crc32(s): 82 | return (~binascii.crc32(s,-1))&0xFFFFFFFF 83 | 84 | def checksumPid(s): 85 | crc = crc32(s) 86 | crc = crc ^ (crc >> 16) 87 | res = s 88 | l = len(letters) 89 | for i in (0,1): 90 | b = crc & 0xff 91 | pos = (b // l) ^ (b % l) 92 | res += letters[pos%l] 93 | crc >>= 8 94 | 95 | return res 96 | 97 | def pidFromSerial(s, l): 98 | crc = crc32(s) 99 | 100 | arr1 = [0]*l 101 | for i in xrange(len(s)): 102 | arr1[i%l] ^= ord(s[i]) 103 | 104 | crc_bytes = [crc >> 24 & 0xff, crc >> 16 & 0xff, crc >> 8 & 0xff, crc & 0xff] 105 | for i in xrange(l): 106 | arr1[i] ^= crc_bytes[i&3] 107 | 108 | pid = '' 109 | for i in xrange(l): 110 | b = arr1[i] & 0xff 111 | pid+=letters[(b >> 7) + ((b >> 5 & 3) ^ (b & 0x1f))] 112 | 113 | return pid 114 | 115 | def cli_main(): 116 | print u"Mobipocket PID calculator for Amazon Kindle. Copyright © 2007, 2009 Igor Skochinsky" 117 | argv=unicode_argv() 118 | if len(argv)==2: 119 | serial = argv[1] 120 | else: 121 | print u"Usage: kindlepid.py /" 122 | return 1 123 | if len(serial)==16: 124 | if serial.startswith("B") or serial.startswith("9"): 125 | print u"Kindle serial number detected" 126 | else: 127 | print u"Warning: unrecognized serial number. Please recheck input." 128 | return 1 129 | pid = pidFromSerial(serial.encode("utf-8"),7)+'*' 130 | print u"Mobipocket PID for Kindle serial#{0} is {1}".format(serial,checksumPid(pid)) 131 | return 0 132 | elif len(serial)==40: 133 | print u"iPhone serial number (UDID) detected" 134 | pid = pidFromSerial(serial.encode("utf-8"),8) 135 | print u"Mobipocket PID for iPhone serial#{0} is {1}".format(serial,checksumPid(pid)) 136 | return 0 137 | print u"Warning: unrecognized serial number. Please recheck input." 138 | return 1 139 | 140 | 141 | if __name__ == "__main__": 142 | sys.stdout=SafeUnbuffered(sys.stdout) 143 | sys.stderr=SafeUnbuffered(sys.stderr) 144 | sys.exit(cli_main()) 145 | -------------------------------------------------------------------------------- /dedrm_src/subasyncio.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab 3 | 4 | import os, sys 5 | import signal 6 | import threading 7 | import subprocess 8 | from subprocess import Popen, PIPE, STDOUT 9 | 10 | # **heavily** chopped up and modfied version of asyncproc.py 11 | # to make it actually work on Windows as well as Mac/Linux 12 | # For the original see: 13 | # "http://www.lysator.liu.se/~bellman/download/" 14 | # author is "Thomas Bellman " 15 | # available under GPL version 3 or Later 16 | 17 | # create an asynchronous subprocess whose output can be collected in 18 | # a non-blocking manner 19 | 20 | # What a mess! Have to use threads just to get non-blocking io 21 | # in a cross-platform manner 22 | 23 | # luckily all thread use is hidden within this class 24 | 25 | class Process(object): 26 | def __init__(self, *params, **kwparams): 27 | if len(params) <= 3: 28 | kwparams.setdefault('stdin', subprocess.PIPE) 29 | if len(params) <= 4: 30 | kwparams.setdefault('stdout', subprocess.PIPE) 31 | if len(params) <= 5: 32 | kwparams.setdefault('stderr', subprocess.PIPE) 33 | self.__pending_input = [] 34 | self.__collected_outdata = [] 35 | self.__collected_errdata = [] 36 | self.__exitstatus = None 37 | self.__lock = threading.Lock() 38 | self.__inputsem = threading.Semaphore(0) 39 | self.__quit = False 40 | 41 | self.__process = subprocess.Popen(*params, **kwparams) 42 | 43 | if self.__process.stdin: 44 | self.__stdin_thread = threading.Thread( 45 | name="stdin-thread", 46 | target=self.__feeder, args=(self.__pending_input, 47 | self.__process.stdin)) 48 | self.__stdin_thread.setDaemon(True) 49 | self.__stdin_thread.start() 50 | 51 | if self.__process.stdout: 52 | self.__stdout_thread = threading.Thread( 53 | name="stdout-thread", 54 | target=self.__reader, args=(self.__collected_outdata, 55 | self.__process.stdout)) 56 | self.__stdout_thread.setDaemon(True) 57 | self.__stdout_thread.start() 58 | 59 | if self.__process.stderr: 60 | self.__stderr_thread = threading.Thread( 61 | name="stderr-thread", 62 | target=self.__reader, args=(self.__collected_errdata, 63 | self.__process.stderr)) 64 | self.__stderr_thread.setDaemon(True) 65 | self.__stderr_thread.start() 66 | 67 | def pid(self): 68 | return self.__process.pid 69 | 70 | def kill(self, signal): 71 | self.__process.send_signal(signal) 72 | 73 | # check on subprocess (pass in 'nowait') to act like poll 74 | def wait(self, flag): 75 | if flag.lower() == 'nowait': 76 | rc = self.__process.poll() 77 | else: 78 | rc = self.__process.wait() 79 | if rc != None: 80 | if self.__process.stdin: 81 | self.closeinput() 82 | if self.__process.stdout: 83 | self.__stdout_thread.join() 84 | if self.__process.stderr: 85 | self.__stderr_thread.join() 86 | return self.__process.returncode 87 | 88 | def terminate(self): 89 | if self.__process.stdin: 90 | self.closeinput() 91 | self.__process.terminate() 92 | 93 | # thread gets data from subprocess stdout 94 | def __reader(self, collector, source): 95 | while True: 96 | data = os.read(source.fileno(), 65536) 97 | self.__lock.acquire() 98 | collector.append(data) 99 | self.__lock.release() 100 | if data == "": 101 | source.close() 102 | break 103 | return 104 | 105 | # thread feeds data to subprocess stdin 106 | def __feeder(self, pending, drain): 107 | while True: 108 | self.__inputsem.acquire() 109 | self.__lock.acquire() 110 | if not pending and self.__quit: 111 | drain.close() 112 | self.__lock.release() 113 | break 114 | data = pending.pop(0) 115 | self.__lock.release() 116 | drain.write(data) 117 | 118 | # non-blocking read of data from subprocess stdout 119 | def read(self): 120 | self.__lock.acquire() 121 | outdata = "".join(self.__collected_outdata) 122 | del self.__collected_outdata[:] 123 | self.__lock.release() 124 | return outdata 125 | 126 | # non-blocking read of data from subprocess stderr 127 | def readerr(self): 128 | self.__lock.acquire() 129 | errdata = "".join(self.__collected_errdata) 130 | del self.__collected_errdata[:] 131 | self.__lock.release() 132 | return errdata 133 | 134 | # non-blocking write to stdin of subprocess 135 | def write(self, data): 136 | if self.__process.stdin is None: 137 | raise ValueError("Writing to process with stdin not a pipe") 138 | self.__lock.acquire() 139 | self.__pending_input.append(data) 140 | self.__inputsem.release() 141 | self.__lock.release() 142 | 143 | # close stdinput of subprocess 144 | def closeinput(self): 145 | self.__lock.acquire() 146 | self.__quit = True 147 | self.__inputsem.release() 148 | self.__lock.release() 149 | -------------------------------------------------------------------------------- /contrib/DeDRM_Macintosh_Application/DeDRM ReadMe.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1561\cocoasubrtf600 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fnil\fcharset134 STHeitiSC-Light;} 3 | {\colortbl;\red255\green255\blue255;} 4 | {\*\expandedcolortbl;;} 5 | \paperw11900\paperh16840\vieww12000\viewh15840\viewkind0 6 | \deftab720 7 | \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\qc\partightenfactor0 8 | 9 | \f0\b\fs24 \cf0 DeDRM ReadMe 10 | \b0 \ 11 | \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\qj\partightenfactor0 12 | 13 | \b \cf0 \ 14 | \ 15 | DeDRM is now a 64-bit application for Mac OS X 10.6 and later. 16 | \b0 \ 17 | \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\partightenfactor0 18 | \cf0 \ 19 | \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\partightenfactor0 20 | 21 | \b \cf0 First Use for Mac OS X 10.9 and later\ 22 | \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\partightenfactor0 23 | 24 | \b0 \cf0 The application is not signed, so the first time you run it you will need to change your security options, or hold down the option key when double-clicking on the icon, or control-click or right-button to get the contextual menu to open it. For later versions, after trying to run it once, you may need to go to the security options of the control panel and give explicit permission for this application to be run.\ 25 | \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\partightenfactor0 26 | 27 | \b \cf0 \ 28 | \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\qj\partightenfactor0 29 | 30 | \b0 \cf0 DeDRM is an application that packs all of the python dm removal software into one easy to use program that remembers preferences and settings.\ 31 | It works without manual configuration with Kindle for Mac ebooks, Adobe Digital Editions Adept ePub and PDF ebooks, and Barnes & Noble NOOK Study ebooks.\ 32 | \ 33 | To remove the DRM of Kindle ebooks from eInk Kindles, other Barnes & Noble ePubs, eReader pdb ebooks, or Mobipocket ebooks, you must first run DeDRM application (by double-clicking it) and set some additional Preferences, depending on the origin of your ebook files:\ 34 | \ 35 | 36 | \b eInk Kindle (not Kindle Fire) 37 | \b0 : 38 | \b \ 39 | 40 | \b0 16 digit Serial Number, found in your Amazon account web pages.\ 41 | 42 | \b Barnes & Noble (not from NOOK Study) 43 | \b0 : \ 44 | Your account email and password, so the key can be retrieved from the Barnes & Noble servers.\ 45 | An active internet connection is required for this.\ 46 | 47 | \b eReader 48 | \b0 :\ 49 | Name and last 8 digits of CC number\ 50 | 51 | \b Mobipocket 52 | \b0 :\ 53 | 10 digit PID\ 54 | \ 55 | A final preference is the destination folder for the DRM-free copies of your ebooks that the application produces. This can be either the same folder as the original ebook, or a folder of your choice.\ 56 | \ 57 | Once these preferences have been set, you can drag and drop ebooks (or folders of ebooks) onto the DeDRM droplet to remove the DRM.\ 58 | \ 59 | This program uses notifications, so really needs Mac OS X 10.8 or above.\ 60 | \ 61 | \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\partightenfactor0 62 | 63 | \b \cf0 Installation 64 | \b0 \ 65 | Drag the DeDRM application from from the DeDRM_Application_Macintosh folder (the location of this ReadMe) to your Applications folder, or anywhere else you find convenient.\ 66 | \ 67 | \ 68 | 69 | \b \ 70 | Use 71 | \b0 \ 72 | 1. To set the preferences, double-click the application and follow the instructions in the dialogs.\ 73 | 2. Drag & Drop DRMed ebooks or folders of DRMed ebooks onto the application icon when it is not running.\ 74 | \ 75 | \ 76 | 77 | \b Troubleshooting\ 78 | \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\partightenfactor0 79 | 80 | \b0 \cf0 A log is created on your desktop (DeDRM.log) containing detailed information from all the scripts. If you have any problems decrypting your ebooks, copy the contents of this log in a comment at Apprentice Alf's blog.\ 81 | \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\partightenfactor0 82 | {\field{\*\fldinst{HYPERLINK "http://apprenticealf.wordpress.com/"}}{\fldrslt \cf0 http://apprenticealf.wordpress.com/}}\ 83 | \ 84 | \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\partightenfactor0 85 | 86 | \b \cf0 Credits\ 87 | \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardeftab720\partightenfactor0 88 | 89 | \b0 \cf0 The original inept and ignoble scripts were by i 90 | \f1 \uc0\u9829 91 | \f0 cabbages\ 92 | The original mobidedrm and erdr2pml scripts were by The Dark Reverser\ 93 | The original topaz DRM removal script was by CMBDTC\ 94 | The original topaz format conversion scripts were by some_updates, clarknova and Bart Simpson\ 95 | \ 96 | The alfcrypto library is by some_updates\ 97 | The ePub encryption detection script is by Apprentice Alf, adapted from a script by Paul Durrant\ 98 | The ignoblekey script is by Apprentice Harper\ 99 | The DeDRM AppleScript is by Apprentice Alf and Apprentice Harper, adapted from a script by Paul Durrant\ 100 | \ 101 | Many fixes, updates and enhancements to the scripts and applications have been made by many other people. For more details, see the comments in the individual scripts.\ 102 | } -------------------------------------------------------------------------------- /dedrm_src/DeDRM_Help.htm: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | DeDRM Plugin Configuration 9 | 16 | 17 | 18 | 19 | 20 |

DeDRM Plugin (v6.3.0)

21 | 22 |

This plugin removes DRM from ebooks when they are imported into calibre. If you already have DRMed ebooks in your calibre library, you will need to remove them and import them again.

23 | 24 |

Installation

25 |

You have obviously managed to install the plugin, as otherwise you wouldn’t be reading this help file. However, you should also delete any older DeDRM plugins, as this DeDRM plugin replaces the five older plugins: Kindle and Mobipocket DeDRM (K4MobiDeDRM), Ignoble Epub DeDRM (ignobleepub), Inept Epub DeDRM (ineptepub), Inept PDF DeDRM (ineptepub) and eReader PDB 2 PML (eReaderPDB2PML).

26 | 27 |

Configuration

28 |

On Windows and Mac, the keys for ebooks downloaded for Kindle for Mac/PC and Adobe Digital Editions are automatically generated. If all your DRMed ebooks can be opened and read in Kindle for Mac/PC and/or Adobe Digital Editions on the same computer on which you are running calibre, you do not need to do any configuration of this plugin. On Linux, keys for Kindle for PC and Adobe Digital Editions need to be generated separately (see the Linux section below)

29 | 30 |

If you have other DRMed ebooks, you will need to enter extra configuration information. The buttons in this dialog will open individual configuration dialogs that will allow you to enter the needed information, depending on the type and source of your DRMed eBooks. Additional help on the information required is available in each of the the dialogs.

31 | 32 |

If you have used previous versions of the various DeDRM plugins on this machine, you may find that some of the configuration dialogs already contain the information you entered through those previous plugins.

33 | 34 |

When you have finished entering your configuration information, you must click the OK button to save it. If you click the Cancel button, all your changes in all the configuration dialogs will be lost.

35 | 36 |

Troubleshooting:

37 | 38 |

If you find that it’s not working for you , you can save a lot of time by trying to add the ebook to Calibre in debug mode. This will print out a lot of helpful info that can be copied into any online help requests.

39 | 40 |

Open a command prompt (terminal window) and type "calibre-debug -g" (without the quotes). Calibre will launch, and you can can add the problem ebook the usual way. The debug info will be output to the original command prompt (terminal window). Copy the resulting output and paste it into the comment you make at my blog.

41 |

Note: The Mac version of Calibre doesn’t install the command line tools by default. If you go to the ‘Preferences’ page and click on the miscellaneous button, you’ll find the option to install the command line tools.

42 | 43 |

Credits:

44 |
    45 |
  • The Dark Reverser for the Mobipocket and eReader scripts
  • 46 |
  • i♥cabbages for the Adobe Digital Editions scripts
  • 47 |
  • Skindle aka Bart Simpson for the Amazon Kindle for PC script
  • 48 |
  • CMBDTC for Amazon Topaz DRM removal script
  • 49 |
  • some_updates, clarknova and Bart Simpson for Amazon Topaz conversion scripts
  • 50 |
  • DiapDealer for the first calibre plugin versions of the tools
  • 51 |
  • some_updates, DiapDealer, Apprentice Alf and mdlnx for Amazon Kindle/Mobipocket tools
  • 52 |
  • some_updates for the DeDRM all-in-one Python tool
  • 53 |
  • Apprentice Alf for the DeDRM all-in-one AppleScript tool
  • 54 |
  • Apprentice Alf for the DeDRM all-in-one calibre plugin
  • 55 |
  • And probably many more.
  • 56 |
57 | 58 |

For additional help read the FAQs at Apprentice Harpers’s GitHub repository. You can ask questions in the comments section of the first post at Apprentice Alf's blog or raise an issue.

59 | 60 |

Linux Systems Only

61 |

Generating decryption keys for Adobe Digital Editions and Kindle for PC

62 |

If you install Kindle for PC and/or Adobe Digital Editions in Wine, you will be able to download DRMed ebooks to them under Wine. To be able to remove the DRM, you will need to generate key files and add them in the plugin's customisation dialogs.

63 | 64 |

To generate the key files you will need to install Python and PyCrypto under the same Wine setup as your Kindle for PC and/or Adobe Digital Editions installations. (Kindle for PC, Python and Pycrypto installation instructions in the ReadMe.)

65 | 66 |

Once everything's installed under Wine, you'll need to run the adobekey.pyw script (for Adobe Digital Editions) and kindlekey.pyw (For Kindle for PC) using the python installation in your Wine system. The scripts can be found in Other_Tools/Key_Retrieval_Scripts.

67 | 68 |

Each script will create a key file in the same folder as the script. Copy the key files to your Linux system and then load the key files using the Adobe Digital Editions ebooks dialog and the Kindle for Mac/PC ebooks dialog.

69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /contrib/Other_Tools/Kindle_for_Android_Patches/kindle_version_4.8.1.10/kindle4.8.1.10.patch: -------------------------------------------------------------------------------- 1 | diff --git a/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali b/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali 2 | index 8ea400e..3aefad2 100644 3 | --- a/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali 4 | +++ b/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali 5 | @@ -41,6 +41,8 @@ 6 | 7 | .field private security:Lcom/mobipocket/android/library/reader/AndroidSecurity; 8 | 9 | +.field private pidList:Ljava/lang/String; 10 | + 11 | .field private totalMemory:J 12 | 13 | 14 | @@ -74,6 +76,10 @@ 15 | .line 133 16 | iput-object p1, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->security:Lcom/mobipocket/android/library/reader/AndroidSecurity; 17 | 18 | + const-string v0, "Open DRMed book to show PID list." 19 | + 20 | + iput-object v0, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String; 21 | + 22 | .line 134 23 | sget-object v0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->TAG:Ljava/lang/String; 24 | 25 | @@ -1339,3 +1345,26 @@ 26 | 27 | return-wide v0 28 | .end method 29 | + 30 | +.method public getPidList()Ljava/lang/String; 31 | + .locals 1 32 | + 33 | + .prologue 34 | + .line 15 35 | + iget-object v0, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String; 36 | + 37 | + return-object v0 38 | +.end method 39 | + 40 | +.method public setPidList(Ljava/lang/String;)V 41 | + .locals 0 42 | + .param p1, "value" 43 | + 44 | + .prologue 45 | + .line 11 46 | + iput-object p1, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String; 47 | + 48 | + .line 12 49 | + return-void 50 | +.end method 51 | + 52 | diff --git a/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali b/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali 53 | index e4a3523..2269fab 100644 54 | --- a/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali 55 | +++ b/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali 56 | @@ -30,3 +30,9 @@ 57 | 58 | .method public abstract getPid()Ljava/lang/String; 59 | .end method 60 | + 61 | +.method public abstract getPidList()Ljava/lang/String; 62 | +.end method 63 | + 64 | +.method public abstract setPidList(Ljava/lang/String;)V 65 | +.end method 66 | diff --git a/smali/com/amazon/kcp/info/AboutActivity.smali b/smali/com/amazon/kcp/info/AboutActivity.smali 67 | index 5640e9e..e298341 100644 68 | --- a/smali/com/amazon/kcp/info/AboutActivity.smali 69 | +++ b/smali/com/amazon/kcp/info/AboutActivity.smali 70 | @@ -493,6 +493,57 @@ 71 | return-void 72 | .end method 73 | 74 | +.method private populatePIDList()V 75 | + .locals 7 76 | + 77 | + .prologue 78 | + .line 313 79 | + invoke-static {}, Lcom/amazon/kcp/application/DeviceInformationProviderFactory;->getProvider()Lcom/amazon/kcp/application/IDeviceInformationProvider; 80 | + 81 | + move-result-object v0 82 | + 83 | + invoke-interface {v0}, Lcom/amazon/kcp/application/IDeviceInformationProvider;->getPidList()Ljava/lang/String; 84 | + 85 | + move-result-object v1 86 | + 87 | + .line 314 88 | + .local v1, "PidList":Ljava/lang/String; 89 | + iget-object v3, p0, Lcom/amazon/kcp/info/AboutActivity;->groupItemList:Ljava/util/List; 90 | + 91 | + new-instance v4, Lcom/amazon/kcp/info/AboutActivity$GroupItem; 92 | + 93 | + const-string v5, "PID List" 94 | + 95 | + const v6, 0x1 96 | + 97 | + invoke-direct {v4, p0, v5, v6}, Lcom/amazon/kcp/info/AboutActivity$GroupItem;->(Lcom/amazon/kcp/info/AboutActivity;Ljava/lang/String;Z)V 98 | + 99 | + invoke-interface {v3, v4}, Ljava/util/List;->add(Ljava/lang/Object;)Z 100 | + 101 | + .line 315 102 | + new-instance v2, Ljava/util/ArrayList; 103 | + 104 | + invoke-direct {v2}, Ljava/util/ArrayList;->()V 105 | + 106 | + .line 316 107 | + .local v2, "children":Ljava/util/List;,"Ljava/util/List;" 108 | + new-instance v3, Lcom/amazon/kcp/info/AboutActivity$DetailItem; 109 | + 110 | + const-string v4, "PIDs" 111 | + 112 | + invoke-direct {v3, p0, v4, v1}, Lcom/amazon/kcp/info/AboutActivity$DetailItem;->(Lcom/amazon/kcp/info/AboutActivity;Ljava/lang/String;Ljava/lang/String;)V 113 | + 114 | + invoke-interface {v2, v3}, Ljava/util/List;->add(Ljava/lang/Object;)Z 115 | + 116 | + .line 317 117 | + iget-object v3, p0, Lcom/amazon/kcp/info/AboutActivity;->detailItemList:Ljava/util/List; 118 | + 119 | + invoke-interface {v3, v2}, Ljava/util/List;->add(Ljava/lang/Object;)Z 120 | + 121 | + .line 318 122 | + return-void 123 | +.end method 124 | + 125 | .method private populateDisplayItems()V 126 | .locals 1 127 | 128 | @@ -538,6 +589,8 @@ 129 | .line 173 130 | invoke-direct {p0}, Lcom/amazon/kcp/info/AboutActivity;->populateDisplayInformation()V 131 | 132 | + invoke-direct {p0}, Lcom/amazon/kcp/info/AboutActivity;->populatePIDList()V 133 | + 134 | .line 174 135 | return-void 136 | 137 | diff --git a/smali/com/amazon/system/security/Security.smali b/smali/com/amazon/system/security/Security.smali 138 | index 04ea997..e88fe08 100644 139 | --- a/smali/com/amazon/system/security/Security.smali 140 | +++ b/smali/com/amazon/system/security/Security.smali 141 | @@ -940,6 +940,16 @@ 142 | 143 | aput-object v0, v6, v8 144 | 145 | + invoke-static {}, Lcom/amazon/kcp/application/DeviceInformationProviderFactory;->getProvider()Lcom/amazon/kcp/application/IDeviceInformationProvider; 146 | + 147 | + move-result-object v5 148 | + 149 | + invoke-static {v6}, Ljava/util/Arrays;->toString([Ljava/lang/Object;)Ljava/lang/String; 150 | + 151 | + move-result-object v2 152 | + 153 | + invoke-interface {v5, v2}, Lcom/amazon/kcp/application/IDeviceInformationProvider;->setPidList(Ljava/lang/String;)V 154 | + 155 | .line 347 156 | return-object v6 157 | .end method -------------------------------------------------------------------------------- /contrib/Other_Tools/Kindle_for_Android_Patches/kindle_version_3.7.0.108/kindle3.7.0.108.patch: -------------------------------------------------------------------------------- 1 | diff -ru kindle3.7.0.108_orig/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali kindle3.7.0.108/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali 2 | --- kindle3.7.0.108_orig/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali 3 | +++ kindle3.7.0.108/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali 4 | @@ -43,6 +43,8 @@ 5 | 6 | .field private security:Lcom/mobipocket/android/library/reader/AndroidSecurity; 7 | 8 | +.field private pidList:Ljava/lang/String; 9 | + 10 | .field private totalMemory:J 11 | 12 | 13 | @@ -78,6 +80,10 @@ 14 | 15 | .line 132 16 | iput-object p2, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->deviceType:Lcom/amazon/kcp/application/AmazonDeviceType; 17 | + 18 | + const-string v0, "Open DRMed book to show PID list." 19 | + 20 | + iput-object v0, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String; 21 | 22 | .line 133 23 | sget-object v0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->TAG:Ljava/lang/String; 24 | @@ -1242,3 +1248,25 @@ 25 | 26 | return-wide v0 27 | .end method 28 | + 29 | +.method public getPidList()Ljava/lang/String; 30 | + .locals 1 31 | + 32 | + .prologue 33 | + .line 15 34 | + iget-object v0, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String; 35 | + 36 | + return-object v0 37 | +.end method 38 | + 39 | +.method public setPidList(Ljava/lang/String;)V 40 | + .locals 0 41 | + .parameter "value" 42 | + 43 | + .prologue 44 | + .line 11 45 | + iput-object p1, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String; 46 | + 47 | + .line 12 48 | + return-void 49 | +.end method 50 | \ No newline at end of file 51 | diff -ru kindle3.7.0.108_orig/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali kindle3.7.0.108/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali 52 | --- kindle3.7.0.108_orig/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali 53 | +++ kindle3.7.0.108/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali 54 | @@ -30,3 +30,9 @@ 55 | 56 | .method public abstract getPid()Ljava/lang/String; 57 | .end method 58 | + 59 | +.method public abstract getPidList()Ljava/lang/String; 60 | +.end method 61 | + 62 | +.method public abstract setPidList(Ljava/lang/String;)V 63 | +.end method 64 | \ No newline at end of file 65 | diff -ru kindle3.7.0.108_orig/smali/com/amazon/kcp/info/AboutActivity.smali kindle3.7.0.108/smali/com/amazon/kcp/info/AboutActivity.smali 66 | --- kindle3.7.0.108_orig/smali/com/amazon/kcp/info/AboutActivity.smali 67 | +++ kindle3.7.0.108/smali/com/amazon/kcp/info/AboutActivity.smali 68 | @@ -493,6 +493,57 @@ 69 | return-void 70 | .end method 71 | 72 | +.method private populatePIDList()V 73 | + .locals 7 74 | + 75 | + .prologue 76 | + .line 313 77 | + invoke-static {}, Lcom/amazon/kcp/application/DeviceInformationProviderFactory;->getProvider()Lcom/amazon/kcp/application/IDeviceInformationProvider; 78 | + 79 | + move-result-object v0 80 | + 81 | + invoke-interface {v0}, Lcom/amazon/kcp/application/IDeviceInformationProvider;->getPidList()Ljava/lang/String; 82 | + 83 | + move-result-object v1 84 | + 85 | + .line 314 86 | + .local v1, PidList:Ljava/lang/String; 87 | + iget-object v3, p0, Lcom/amazon/kcp/info/AboutActivity;->groupItemList:Ljava/util/List; 88 | + 89 | + new-instance v4, Lcom/amazon/kcp/info/AboutActivity$GroupItem; 90 | + 91 | + const-string v5, "PID List" 92 | + 93 | + const v6, 0x1 94 | + 95 | + invoke-direct {v4, p0, v5, v6}, Lcom/amazon/kcp/info/AboutActivity$GroupItem;->(Lcom/amazon/kcp/info/AboutActivity;Ljava/lang/String;Z)V 96 | + 97 | + invoke-interface {v3, v4}, Ljava/util/List;->add(Ljava/lang/Object;)Z 98 | + 99 | + .line 315 100 | + new-instance v2, Ljava/util/ArrayList; 101 | + 102 | + invoke-direct {v2}, Ljava/util/ArrayList;->()V 103 | + 104 | + .line 316 105 | + .local v2, children:Ljava/util/List;,"Ljava/util/List;" 106 | + new-instance v3, Lcom/amazon/kcp/info/AboutActivity$DetailItem; 107 | + 108 | + const-string v4, "PIDs" 109 | + 110 | + invoke-direct {v3, p0, v4, v1}, Lcom/amazon/kcp/info/AboutActivity$DetailItem;->(Lcom/amazon/kcp/info/AboutActivity;Ljava/lang/String;Ljava/lang/String;)V 111 | + 112 | + invoke-interface {v2, v3}, Ljava/util/List;->add(Ljava/lang/Object;)Z 113 | + 114 | + .line 317 115 | + iget-object v3, p0, Lcom/amazon/kcp/info/AboutActivity;->detailItemList:Ljava/util/List; 116 | + 117 | + invoke-interface {v3, v2}, Ljava/util/List;->add(Ljava/lang/Object;)Z 118 | + 119 | + .line 318 120 | + return-void 121 | +.end method 122 | + 123 | .method private populateDisplayItems()V 124 | .locals 1 125 | 126 | @@ -539,6 +590,9 @@ 127 | invoke-direct {p0}, Lcom/amazon/kcp/info/AboutActivity;->populateDisplayInformation()V 128 | 129 | .line 190 130 | + invoke-direct {p0}, Lcom/amazon/kcp/info/AboutActivity;->populatePIDList()V 131 | + 132 | + .line 191 133 | return-void 134 | 135 | .line 172 136 | diff -ru kindle3.7.0.108_orig/smali/com/amazon/system/security/Security.smali kindle3.7.0.108/smali/com/amazon/system/security/Security.smali 137 | --- kindle3.7.0.108_orig/smali/com/amazon/system/security/Security.smali 138 | +++ kindle3.7.0.108/smali/com/amazon/system/security/Security.smali 139 | @@ -926,6 +926,16 @@ 140 | sget-object v0, Lcom/amazon/system/security/Security;->CUSTOM_PID_FOR_BUNDLED_DICTIONARY_DRM:Ljava/lang/String; 141 | 142 | aput-object v0, v6, v8 143 | + 144 | + invoke-static {}, Lcom/amazon/kcp/application/DeviceInformationProviderFactory;->getProvider()Lcom/amazon/kcp/application/IDeviceInformationProvider; 145 | + 146 | + move-result-object v5 147 | + 148 | + invoke-static {v6}, Ljava/util/Arrays;->toString([Ljava/lang/Object;)Ljava/lang/String; 149 | + 150 | + move-result-object v2 151 | + 152 | + invoke-interface {v5, v2}, Lcom/amazon/kcp/application/IDeviceInformationProvider;->setPidList(Ljava/lang/String;)V 153 | 154 | .line 353 155 | return-object v6 156 | -------------------------------------------------------------------------------- /contrib/Other_Tools/Kindle_for_Android_Patches/A_Patching_Experience.txt: -------------------------------------------------------------------------------- 1 | Of Historical Interest Only 2 | =========================== 3 | 4 | It is now much simpler and easier to get a backup.ab file from your Android device and import that into the tools. 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Comment at Apprentice Alf's Blog by cestmoicestmoi, 21st December, 2012. 13 | ======================================================================== 14 | 15 | just to share my experience in patching the kindle.apk 16 | 17 | first thanks to all of you guys for this great site & tools, keep going 18 | 19 | following instructions in latest readme.txt 20 | successfully patched Android Kindle 3.7.0.108, Android 2.3.4 Xperia Arc unrooted; 21 | key painful snags encountered in my case (+ had never coded java/built any apk! .apk = app on Android) (just sums up here the tip of the iceberg): 22 | on phone : 23 | to get the app kindle.apk (invisible in unrooted phones) : 24 | use MyAppShare (free), but this required old Kindle.apk version (for patching) won’t probably be in your phone anymore (latest today 3.8.1.11, with new updates almost everyday !) 25 | anyway in any-case turnoff the Play-Store auto update 26 | otherwise/then look for a 3.7.0.108 on the web (or try patch a newer one ?) 27 | reminder: .apk are just containers = zip files… to check just add an extra .zip and unzip kindle.apk, but don’t play with that… patching wouldn’t work; however all names of kindle.apk can be completely freely changed : kindle2patchedJojo.apk, com.amazon.kindle.apk, etc. 28 | on your PC (XP): 29 | rather long & tricky expert process for any non-android-app maker 30 | (basics is to use the cmd.exe very old DOS style command line with the tricky path and directories changes, forward and back slash etc etc !) 31 | pb to obtain all the necessary .exe tools (then you call them as a ‘command’ in cdm.exe) 32 | to make things easier, put copy of everything in same folder anywhere: 33 | kindle.apk, cmd.exe (from XP), apktool.jar+apktool.bat+aapt.exe (from http://code.google.com/p/android-apktool/), patch.exe (from http://gnuwin32.sourceforge.net/packages/patch.htm), keytool.exe+jarsign.exe(from http://www.oracle.com/technetwork/java/javase/downloads/ download JDK+JRE same recent version, in my case v6038; start with keytool then jarsign; keep these .exe in their java/…/bin files, make shortcuts, copy them in your “work” folder, then do the path thing in cmd.exe in just copying the paths in the properties of the shortcuts) 34 | then, key points: 35 | download/use apktool.jar v143 not v150 (version seen in calling from cdm.exe) 36 | do not “apktool if…” (frameworks) 37 | besides all cmd.exe commands given in the readme.txt (read both .txt the old and the newer, even if same name) are perfectly ok (except in keytool: a typo: -valkeidity is -validity; and -genkey preferably -genkeypair) 38 | (for the tricky keytool then jarsign stuff better read for ex. https://www.owasp.org/index.php/Signing_jar_files_with_jarsigner) 39 | (almost1) finally move your patched & signed new kindle.apk anywhere to phone sd card, and then from within android just like possibly for any .apk move to it with any file manager and click it, it installs by itself (mine didn’t want to install over the non-patched kindle app, so I had to desinstall the latter 1st from within the settings, but it’s probably because my phone ram was full !) 40 | (almost2) finally you get your famous PIDs at the bottom of the info in the kindle.apk: don’t worry, in my test case (just 1 book yet), there were 11 PIDs, but 5 were redundant, and the last is a weird large neg number -obviously not a 10 max char. PID, so forget it-). 41 | then thanks to Android 2.3.4 now you can screenshot (press power button then back button), then from my PC i got this screen pict with all these PIDs, which I even OCRised (stupidly without checking… so I mixed up some “O” and “0″ etc !), 42 | (almost3) finally then I implemented these PIDs in deDRM v541, …and it didn’t work, long error message, but, finally, at last, worked in deDRM v531 ! 43 | 44 | conclusion: 45 | the idea and work behind this patch is brilliant… but I have the bad feeling that most of this/my rather crazy work above to do myself the whole patching thing was more for glory, like climbing some kind of Everest without any training, than anything else… 46 | must precise that I have only an old mac-ppc + this Android phone; ppc has no kindle.app available*; ppc has no java 1.6 so no possible apktool etc. (nor eclipse Android plugin etc.) (possible with very old versions ?), luckily I had an old version of VPC(virtualpc)/XP (extremely slow!), so I could try all this java stuff at least in a normal XP window/virtual machine, on my mac-ppc; i didn’t try any XP-Android link through USB or else, had only my usual Mac-Android wifi ftp (great direct drag’n drop with cyberduck). 47 | But when i see all these/my efforts described above for a non-specialist (like 1 week work vs. 1-2 hours for you apk developers !), I wonder if this patched apk shouldn’t/couldn’t be made directly available for most other average joes, no ? just like deDRM ? (or maybe i don’t see the problems here ?); 48 | besides, i didn’t check, but i have the strong feeling that in using kindle directly on XP to buy my books, this great app deDRM would have found directly these PIDs or other keys automatically (as it does for me on my mac-ppc for some ebook purchased and downloaded directly from other vendors; i.e. “stupid me”… on XP, the deDRM app would have worked in 1 sec… vs. 1 week work above for patching Android, + the crazy procedure just to get these pids, screenshot + ocr + etc. ! well, it should be much faster now, of course !). 49 | 50 | *reminder: there is a solution for a mac-ppc only guy who want to buy & read Kindle books for very cheap, and accept to read them online in a browser : little advertised “Kindle cloud reader” which used to work even with rather old Safari versions (didn’t check recently if it still works)… (looks a lot like the ‘Google play’ book reader) texts are very little protected/not encrypted there apparently (journalists even said at launch 2-3 years ago that Amazon was abandoning DRMs, just like Apple did with music a while ago) : texts can more or less easily be copied piece by piece/ by page with a few astute clicks (same for Google; but formatting is gone; and who want to recopy a 300 p. book page by page !); tried to reverse engineer a bit for fun this browser reader to see where and how the text was stored, etc. but (as mentioned I think by another in another comment) the text is downloaded only by pieces, not all at once (don’t remember what if browser turned “offline” ?), and stored here and there, in caches… maybe there are tools for capturing auto these books sent to browsers ? didn’t check ? (not for my mac-ppc at the time in any case; but possibly Windows). 51 | -------------------------------------------------------------------------------- /dedrm_src/zipfix.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # zipfix.py, version 1.1 5 | # Copyright © 2010-2013 by some_updates, DiapDealer and Apprentice Alf 6 | 7 | # Released under the terms of the GNU General Public Licence, version 3 8 | # 9 | 10 | # Revision history: 11 | # 1.0 - Initial release 12 | # 1.1 - Updated to handle zip file metadata correctly 13 | 14 | """ 15 | Re-write zip (or ePub) fixing problems with file names (and mimetype entry). 16 | """ 17 | 18 | __license__ = 'GPL v3' 19 | __version__ = "1.1" 20 | 21 | import sys 22 | import zlib 23 | import zipfilerugged 24 | import os 25 | import os.path 26 | import getopt 27 | from struct import unpack 28 | 29 | 30 | _FILENAME_LEN_OFFSET = 26 31 | _EXTRA_LEN_OFFSET = 28 32 | _FILENAME_OFFSET = 30 33 | _MAX_SIZE = 64 * 1024 34 | _MIMETYPE = 'application/epub+zip' 35 | 36 | class ZipInfo(zipfilerugged.ZipInfo): 37 | def __init__(self, *args, **kwargs): 38 | if 'compress_type' in kwargs: 39 | compress_type = kwargs.pop('compress_type') 40 | super(ZipInfo, self).__init__(*args, **kwargs) 41 | self.compress_type = compress_type 42 | 43 | class fixZip: 44 | def __init__(self, zinput, zoutput): 45 | self.ztype = 'zip' 46 | if zinput.lower().find('.epub') >= 0 : 47 | self.ztype = 'epub' 48 | self.inzip = zipfilerugged.ZipFile(zinput,'r') 49 | self.outzip = zipfilerugged.ZipFile(zoutput,'w') 50 | # open the input zip for reading only as a raw file 51 | self.bzf = file(zinput,'rb') 52 | 53 | def getlocalname(self, zi): 54 | local_header_offset = zi.header_offset 55 | self.bzf.seek(local_header_offset + _FILENAME_LEN_OFFSET) 56 | leninfo = self.bzf.read(2) 57 | local_name_length, = unpack(' 0: 66 | if len(cmpdata) > _MAX_SIZE : 67 | newdata = cmpdata[0:_MAX_SIZE] 68 | cmpdata = cmpdata[_MAX_SIZE:] 69 | else: 70 | newdata = cmpdata 71 | cmpdata = '' 72 | newdata = dc.decompress(newdata) 73 | unprocessed = dc.unconsumed_tail 74 | if len(unprocessed) == 0: 75 | newdata += dc.flush() 76 | data += newdata 77 | cmpdata += unprocessed 78 | unprocessed = '' 79 | return data 80 | 81 | def getfiledata(self, zi): 82 | # get file name length and exta data length to find start of file data 83 | local_header_offset = zi.header_offset 84 | 85 | self.bzf.seek(local_header_offset + _FILENAME_LEN_OFFSET) 86 | leninfo = self.bzf.read(2) 87 | local_name_length, = unpack(' 0: 107 | # Remove Python executable and commands if present 108 | start = argc.value - len(sys.argv) 109 | return [argv[i] for i in 110 | xrange(start, argc.value)] 111 | # if we don't have any arguments at all, just pass back script name 112 | # this should never happen 113 | return [u"epubtest.py"] 114 | else: 115 | argvencoding = sys.stdin.encoding 116 | if argvencoding == None: 117 | argvencoding = "utf-8" 118 | return [arg if (type(arg) == unicode) else unicode(arg,argvencoding) for arg in sys.argv] 119 | 120 | _FILENAME_LEN_OFFSET = 26 121 | _EXTRA_LEN_OFFSET = 28 122 | _FILENAME_OFFSET = 30 123 | _MAX_SIZE = 64 * 1024 124 | 125 | 126 | def uncompress(cmpdata): 127 | dc = zlib.decompressobj(-15) 128 | data = '' 129 | while len(cmpdata) > 0: 130 | if len(cmpdata) > _MAX_SIZE : 131 | newdata = cmpdata[0:_MAX_SIZE] 132 | cmpdata = cmpdata[_MAX_SIZE:] 133 | else: 134 | newdata = cmpdata 135 | cmpdata = '' 136 | newdata = dc.decompress(newdata) 137 | unprocessed = dc.unconsumed_tail 138 | if len(unprocessed) == 0: 139 | newdata += dc.flush() 140 | data += newdata 141 | cmpdata += unprocessed 142 | unprocessed = '' 143 | return data 144 | 145 | def getfiledata(file, zi): 146 | # get file name length and exta data length to find start of file data 147 | local_header_offset = zi.header_offset 148 | 149 | file.seek(local_header_offset + _FILENAME_LEN_OFFSET) 150 | leninfo = file.read(2) 151 | local_name_length, = struct.unpack('()V 23 | .locals 1 24 | 25 | .prologue 26 | .line 30 27 | const-class v0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider; 28 | @@ -72,20 +74,24 @@ 29 | .prologue 30 | .line 130 31 | invoke-direct {p0}, Ljava/lang/Object;->()V 32 | 33 | .line 131 34 | iput-object p1, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->security:Lcom/mobipocket/android/library/reader/AndroidSecurity; 35 | 36 | .line 132 37 | iput-object p2, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->deviceType:Lcom/amazon/kcp/application/AmazonDeviceType; 38 | 39 | + const-string v0, "Open DRMed book to show PID list." 40 | + 41 | + iput-object v0, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String; 42 | + 43 | .line 133 44 | sget-object v0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->TAG:Ljava/lang/String; 45 | 46 | new-instance v0, Ljava/lang/StringBuilder; 47 | 48 | invoke-direct {v0}, Ljava/lang/StringBuilder;->()V 49 | 50 | const-string v1, "Device Type is set to \"" 51 | 52 | invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; 53 | @@ -1235,10 +1241,33 @@ 54 | move-result-wide v0 55 | 56 | iput-wide v0, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->totalMemory:J 57 | 58 | .line 308 59 | :cond_0 60 | iget-wide v0, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->totalMemory:J 61 | 62 | return-wide v0 63 | .end method 64 | + 65 | +.method public getPidList()Ljava/lang/String; 66 | + .locals 1 67 | + 68 | + .prologue 69 | + .line 15 70 | + iget-object v0, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String; 71 | + 72 | + return-object v0 73 | +.end method 74 | + 75 | +.method public setPidList(Ljava/lang/String;)V 76 | + .locals 0 77 | + .parameter "value" 78 | + 79 | + .prologue 80 | + .line 11 81 | + iput-object p1, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String; 82 | + 83 | + .line 12 84 | + return-void 85 | +.end method 86 | + 87 | diff -r -u10 kindle4.0.2.1_orig/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali kindle4.0.2.1/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali 88 | --- kindle4.0.2.1_orig/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali 2013-05-22 18:39:03.000000000 -0500 89 | +++ kindle4.0.2.1/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali 2013-05-23 16:55:58.000000000 -0500 90 | @@ -23,10 +23,16 @@ 91 | .end method 92 | 93 | .method public abstract getDeviceTypeId()Ljava/lang/String; 94 | .end method 95 | 96 | .method public abstract getOsVersion()Ljava/lang/String; 97 | .end method 98 | 99 | .method public abstract getPid()Ljava/lang/String; 100 | .end method 101 | + 102 | +.method public abstract getPidList()Ljava/lang/String; 103 | +.end method 104 | + 105 | +.method public abstract setPidList(Ljava/lang/String;)V 106 | +.end method 107 | diff -r -u10 kindle4.0.2.1_orig/smali/com/amazon/kcp/info/AboutActivity.smali kindle4.0.2.1/smali/com/amazon/kcp/info/AboutActivity.smali 108 | --- kindle4.0.2.1_orig/smali/com/amazon/kcp/info/AboutActivity.smali 2013-05-22 18:39:03.000000000 -0500 109 | +++ kindle4.0.2.1/smali/com/amazon/kcp/info/AboutActivity.smali 2013-05-23 17:18:14.000000000 -0500 110 | @@ -486,20 +486,71 @@ 111 | .end local v2 #screenDpi:Ljava/lang/String; 112 | :cond_0 113 | iget-object v5, p0, Lcom/amazon/kcp/info/AboutActivity;->detailItemList:Ljava/util/List; 114 | 115 | invoke-interface {v5, v0}, Ljava/util/List;->add(Ljava/lang/Object;)Z 116 | 117 | .line 317 118 | return-void 119 | .end method 120 | 121 | +.method private populatePIDList()V 122 | + .locals 7 123 | + 124 | + .prologue 125 | + .line 313 126 | + invoke-static {}, Lcom/amazon/kcp/application/DeviceInformationProviderFactory;->getProvider()Lcom/amazon/kcp/application/IDeviceInformationProvider; 127 | + 128 | + move-result-object v0 129 | + 130 | + invoke-interface {v0}, Lcom/amazon/kcp/application/IDeviceInformationProvider;->getPidList()Ljava/lang/String; 131 | + 132 | + move-result-object v1 133 | + 134 | + .line 314 135 | + .local v1, PidList:Ljava/lang/String; 136 | + iget-object v3, p0, Lcom/amazon/kcp/info/AboutActivity;->groupItemList:Ljava/util/List; 137 | + 138 | + new-instance v4, Lcom/amazon/kcp/info/AboutActivity$GroupItem; 139 | + 140 | + const-string v5, "PID List" 141 | + 142 | + const v6, 0x1 143 | + 144 | + invoke-direct {v4, p0, v5, v6}, Lcom/amazon/kcp/info/AboutActivity$GroupItem;->(Lcom/amazon/kcp/info/AboutActivity;Ljava/lang/String;Z)V 145 | + 146 | + invoke-interface {v3, v4}, Ljava/util/List;->add(Ljava/lang/Object;)Z 147 | + 148 | + .line 315 149 | + new-instance v2, Ljava/util/ArrayList; 150 | + 151 | + invoke-direct {v2}, Ljava/util/ArrayList;->()V 152 | + 153 | + .line 316 154 | + .local v2, children:Ljava/util/List;,"Ljava/util/List;" 155 | + new-instance v3, Lcom/amazon/kcp/info/AboutActivity$DetailItem; 156 | + 157 | + const-string v4, "PIDs" 158 | + 159 | + invoke-direct {v3, p0, v4, v1}, Lcom/amazon/kcp/info/AboutActivity$DetailItem;->(Lcom/amazon/kcp/info/AboutActivity;Ljava/lang/String;Ljava/lang/String;)V 160 | + 161 | + invoke-interface {v2, v3}, Ljava/util/List;->add(Ljava/lang/Object;)Z 162 | + 163 | + .line 317 164 | + iget-object v3, p0, Lcom/amazon/kcp/info/AboutActivity;->detailItemList:Ljava/util/List; 165 | + 166 | + invoke-interface {v3, v2}, Ljava/util/List;->add(Ljava/lang/Object;)Z 167 | + 168 | + .line 318 169 | + return-void 170 | +.end method 171 | + 172 | .method private populateDisplayItems()V 173 | .locals 1 174 | 175 | .prologue 176 | .line 171 177 | iget-object v0, p0, Lcom/amazon/kcp/info/AboutActivity;->groupItemList:Ljava/util/List; 178 | 179 | if-nez v0, :cond_0 180 | 181 | .line 173 182 | @@ -531,20 +582,22 @@ 183 | 184 | .line 192 185 | invoke-direct {p0}, Lcom/amazon/kcp/info/AboutActivity;->populateRamInformation()V 186 | 187 | .line 193 188 | invoke-direct {p0}, Lcom/amazon/kcp/info/AboutActivity;->populateStorageInformation()V 189 | 190 | .line 194 191 | invoke-direct {p0}, Lcom/amazon/kcp/info/AboutActivity;->populateDisplayInformation()V 192 | 193 | + invoke-direct {p0}, Lcom/amazon/kcp/info/AboutActivity;->populatePIDList()V 194 | + 195 | .line 195 196 | return-void 197 | 198 | .line 177 199 | :cond_0 200 | iget-object v0, p0, Lcom/amazon/kcp/info/AboutActivity;->groupItemList:Ljava/util/List; 201 | 202 | invoke-interface {v0}, Ljava/util/List;->clear()V 203 | 204 | goto :goto_0 205 | diff -r -u10 kindle4.0.2.1_orig/smali/com/amazon/system/security/Security.smali kindle4.0.2.1/smali/com/amazon/system/security/Security.smali 206 | --- kindle4.0.2.1_orig/smali/com/amazon/system/security/Security.smali 2013-05-22 18:39:04.000000000 -0500 207 | +++ kindle4.0.2.1/smali/com/amazon/system/security/Security.smali 2013-05-23 17:19:05.000000000 -0500 208 | @@ -920,20 +920,30 @@ 209 | 210 | .line 350 211 | :cond_2 212 | add-int/lit8 v8, v8, 0x1 213 | 214 | .line 351 215 | sget-object v0, Lcom/amazon/system/security/Security;->CUSTOM_PID_FOR_BUNDLED_DICTIONARY_DRM:Ljava/lang/String; 216 | 217 | aput-object v0, v6, v8 218 | 219 | + invoke-static {}, Lcom/amazon/kcp/application/DeviceInformationProviderFactory;->getProvider()Lcom/amazon/kcp/application/IDeviceInformationProvider; 220 | + 221 | + move-result-object v5 222 | + 223 | + invoke-static {v6}, Ljava/util/Arrays;->toString([Ljava/lang/Object;)Ljava/lang/String; 224 | + 225 | + move-result-object v2 226 | + 227 | + invoke-interface {v5, v2}, Lcom/amazon/kcp/application/IDeviceInformationProvider;->setPidList(Ljava/lang/String;)V 228 | + 229 | .line 353 230 | return-object v6 231 | .end method 232 | 233 | 234 | # virtual methods 235 | .method public customDrmOnly()I 236 | .locals 1 237 | 238 | .prologue 239 | -------------------------------------------------------------------------------- /contrib/ReadMe_First.txt: -------------------------------------------------------------------------------- 1 | Welcome to the tools! 2 | ===================== 3 | 4 | This ReadMe_First.txt is meant to give users a quick overview of what is available and how to get started. This document is part of the Tools v6.6.2 archive from Apprentice Harper's github repository: https://github.com/apprenticeharper/DeDRM_tools/ 5 | 6 | The is archive includes tools to remove DRM from: 7 | 8 | - Kindle ebooks (files from Kindle for Mac/PC* and eInk Kindles**). 9 | - Adobe Digital Editions (v2.0.1***) ePubs (including Kobo and Google ePubs downloaded to ADE) 10 | - Kobo kePubs from the Kobo Desktop application 11 | - Barnes and Noble ePubs 12 | - Adobe Digital Editions (v2.0.1) PDFs 13 | - Scuolabooks (Link to solution by Hex) 14 | - Mobipocket ebooks 15 | - eReader PDB ebooks 16 | - Rocket ebooks (source only) 17 | 18 | These tools do NOT work with Apple's iBooks FairPlay DRM (see end of this file.) 19 | 20 | * With Kindle for PC/Mac 1.19 and later, Amazon included support for their new KFX format. While the tools now include a first attempt at supporting drm removal for KFX format, we recommend using Kindle for PC/Mac 1.17 or earlier which prevents downloads of the new format, as conversions from the olde KF8 format are likely to be more successful. 21 | 22 | ** Some later Kindles support Amazon's new KFX format. And some books download in a split azw3/azw6 format. For best results, instead of using files downloaded directly to your Kindle, download from Amazon's web site 'for transfer via USB'. This will give you an single file to import. See also the FAQ entry about this. 23 | 24 | *** With Adobe Digital Editions 3.0 and later, Adobe have introduced a new, optional, DRM scheme. To avoid this new scheme, you should use Adobe Digital Editions 2.0.1. Some books are required to use the new DRM scheme and so will not download with ADE 2.0.1. If you still want such a book, you will need to use ADE 3.0 or later to download it, but you should remember that no tools to remove Adobe's new DRM scheme exist as of June 2017. 25 | 26 | About the tools 27 | --------------- 28 | These tools are updated and maintained by Apprentice Harper and many others. You can find the latest updates at Apprentice Harper's github repository https://github.com/apprenticeharper/DeDRM_tools/ and get support by creating an issue at the repository (github account required) or by posting a comment at Apprentice Alf's blog: http://www.apprenticealf.wordpress.com/ 29 | 30 | If you re-post these tools, a link to the repository and/or the blog would be appreciated. 31 | 32 | 33 | DeDRM plugin for calibre (Mac OS X, Windows, and Linux) 34 | ------------------------------------------------------- 35 | Calibre is an open source freeware ebook library manager. It is the best tool around for keeping track of your ebooks. The DeDRM plugin for calibre provides the simplest way, especially on Windows, to remove DRM from your Kindle and Adobe DRM ebooks. Just install the DeDRM plugin from the DeDRM_calibre_plugin folder, following the instructions and configuration directions provided in the ReadMe file and the help links in the plugin's configuration dialogs. 36 | 37 | Once installed and configured, you can simply add a DRM book to calibre and the DRM-free version will be imported into the calibre database. Note that DRM removal only occurs on IMPORT not on CONVERSION or at any other time. If you have already imported DRM books you'll need to remove them from calibre and re-import them. 38 | 39 | For instructions, see the DeDRM_plugin_ReadMe.txt file in the DeDRM_calibre_plugin folder. 40 | 41 | 42 | Obok plugin for calibre (Mac OS X and Windows) 43 | ---------------------------------------------- 44 | To import ebooks from the Kobo Desktop app or from a Kobo ebook reader, install the Obok plugin. This works in a different way to the DeDRM plugin, in that it finds your ebooks downloaded using the Kobo Desktop app, or on an attached Kobo ebooks reader, and displays them in a list, so that you can choose the ones you want to import into calibre. 45 | 46 | For instructions, see the obok_plugin_ReadMe.txt file in the Obok_calibre_plugin folder. 47 | 48 | 49 | DeDRM application for Mac OS X users: (Mac OS X 10.6 and above) 50 | --------------------------------------------------------------- 51 | This application is a stand-alone DRM removal application for Mac OS X users. It is only needed for people who cannot or will not use the calibre plugin. KFX support has not been tested yet. 52 | 53 | For instructions, see the "DeDRM ReadMe.rtf" file in the DeDRM_Macintosh_Application folder. 54 | 55 | 56 | DeDRM application for Windows users: (Windows XP through Windows 10) 57 | ------------------------------------------------------------------ 58 | ***This program requires that Python and PyCrypto be properly installed.*** 59 | ***See below for details on recommended versions and how to install them.*** 60 | 61 | This application is a stand-alone application for Windows users. It is only needed for people who cannot or will not use the calibre plugin. KFX support has not been tested yet. 62 | 63 | For instructions, see the DeDRM_App_ReadMe.txt file in the DeDRM_Windows_Applications folder. 64 | 65 | 66 | Other_Tools 67 | ----------- 68 | This is a folder of other tools that may be useful for DRMed ebooks from certain sources or for Linux users. Most users won't need any of these tools. 69 | 70 | B_and_N_Download_Helper 71 | A Javascript to enable a download button at the B&N website for ebooks that normally won't download to your PC. Only for the adventurous. 72 | 73 | DRM_Key_Scripts 74 | This folder contains python scripts that create or extract or fetch encryption keyfiles for Barnes and Noble, Adobe Digital Editions, Kindle for Mac/PC and old versions of Kindle for Android. 75 | 76 | Kindle_for_Android_Patches 77 | Definitely only for the adventurous, this folder contains information on how to modify the Kindle for Android app to b able to get a PID for use with the other Kindle tools (DeDRM apps and calibre plugin). 78 | 79 | Kobo 80 | Contains the standalone obok python script for removing DRM from kePubs downloaded using the kobo desktop application. 81 | 82 | Rocket_ebooks 83 | Information about the now-obsolete Rocket ebook format and DRM, along with source for a tool to remove the DRM. 84 | 85 | Scuolabook_DRM 86 | A link to the tool for removing DRM from ScuolaBooks PDFs, created by "Hex". 87 | 88 | 89 | Windows and Python 90 | ------------------ 91 | We **strongly** recommend using calibre and the plugin. 92 | 93 | If you really want to use the WIndows app or the individual scripts, you'll need to install python. 94 | ActiveState's Active Python 2.7 Community Edition for Windowscan be downloaded for free from: 95 | 96 | http://www.activestate.com/activepython/downloads 97 | 98 | In addition, Windows Users need PyCrypto: 99 | 100 | There are many places to get PyCrypto installers for Windows. One such place is: 101 | 102 | http://www.voidspace.org.uk/python/modules.shtml 103 | 104 | Please get the latest (currently 2.6) PyCrypto meant for Windows Python version 2.7. Note that the PyCrypto binaries have two version numbers. The first is the PyCrypto version, and the second is the python version that they work with. This can be confusing. 105 | 106 | Once Windows users have installed Python 2.7, and the matching PyCrypto, they are ready to run the DeDRM application or individual scripts. 107 | 108 | For (experimental) KFX support, you also need LZMA support. LZMA is built-in 109 | in Python 3.3+ but not present in Python 2. Choices are backports.lzma and 110 | pylzma, both of which need compiling. Compiling Python extensions on Windows 111 | requires Visual Studio and is a PITA. The recommended way is to install wheels 112 | (binary) directly. 113 | 114 | Windows binary wheels for backports.lzma and pylzma could be found here: 115 | 116 | https://www.lfd.uci.edu/~gohlke/pythonlibs/ 117 | 118 | 119 | Apple's iBooks FairPlay DRM 120 | --------------------------- 121 | 122 | The only tool that removes Apple's iBooks Fairplay DRM is Requiem by Brahms version 3.3.6 and works with iTunes 10.5. Requiem 4.0 and later do not remove DRM from ebooks. 123 | 124 | Requiem is no longer developed as of 2012, with the last version 4.1. 125 | 126 | You can download it from these download links: 127 | 128 | Requiem 3.3.6 for Windows: http://www.datafilehost.com/download-f7916922.html 129 | MD5: 10ab191f2d86c692d57f6a07b4622cf8 130 | 131 | Requiem 3.3.6 for Mac OS X: http://www.datafilehost.com/download-47fce8b7.html 132 | MD5: 6d4167d47e6982ddbb8528212198b520 133 | 134 | Requiem 3.3.6 source code: http://www.datafilehost.com/download-172920e9.html 135 | MD5: 1636862796d573c693d56bcc526b60bd 136 | 137 | No support for requiem is provided at Apprentice Alf's blog or Apprentice Harper's github repository. 138 | 139 | 140 | Credits 141 | ------- 142 | The original inept and ignoble scripts were by i♥cabbages 143 | The original mobidedrm and erdr2pml scripts were by The Dark Reverser 144 | The original topaz DRM removal script was by CMBDTC 145 | The original topaz format conversion scripts were by some_updates, clarknova and Bart Simpson 146 | The original KFX format decryption was by lulzkabulz, converted to python by Apprentice Naomi and integrated into the tools by tomthumb1997 147 | 148 | The original obok script was by Physisticated 149 | 150 | The alfcrypto library is by some_updates 151 | The ePub encryption detection script is by Apprentice Alf, adapted from a script by Paul Durrant 152 | The ignoblekey script is by Apprentice Harper 153 | The DeDRM plugin was based on plugins by DiapDealer and is maintained by Apprentice Alf and Apprentice Harper 154 | The DeDRM AppleScript was by Paul Durrant and is maintained by Apprentice Alf and Apprentice Harper 155 | The DeDRM python GUI was by some_updates and is maintained by Apprentice Alf and Apprentice Harper 156 | 157 | The Scuolabooks tool is by Hex 158 | 159 | Many fixes, updates and enhancements to the scripts and applicatons have been made by many other people. For more details, see the comments in the individual scripts. 160 | -------------------------------------------------------------------------------- /contrib/Other_Tools/DRM_Key_Scripts/Kindle_for_iOS/kindleiospidgen.pyw: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import with_statement 5 | 6 | # kindleforios4key.py 7 | # Copyright © 2013 by Apprentice Alf 8 | # Portions Copyright © 2007, 2009 Igor Skochinsky 9 | 10 | # Revision history: 11 | # 1.0 - Generates fixed PID for Kindle for iOS 3.1.1 running on iOS 4.x 12 | 13 | 14 | """ 15 | Generate fixed PID for Kindle for iOS 3.1.1 16 | """ 17 | 18 | __license__ = 'GPL v3' 19 | __version__ = '1.0' 20 | 21 | import sys, os 22 | import getopt 23 | import binascii 24 | 25 | # Wrap a stream so that output gets flushed immediately 26 | # and also make sure that any unicode strings get 27 | # encoded using "replace" before writing them. 28 | class SafeUnbuffered: 29 | def __init__(self, stream): 30 | self.stream = stream 31 | self.encoding = stream.encoding 32 | if self.encoding == None: 33 | self.encoding = "utf-8" 34 | def write(self, data): 35 | if isinstance(data,unicode): 36 | data = data.encode(self.encoding,"replace") 37 | self.stream.write(data) 38 | self.stream.flush() 39 | def __getattr__(self, attr): 40 | return getattr(self.stream, attr) 41 | 42 | iswindows = sys.platform.startswith('win') 43 | isosx = sys.platform.startswith('darwin') 44 | 45 | def unicode_argv(): 46 | if iswindows: 47 | # Uses shell32.GetCommandLineArgvW to get sys.argv as a list of Unicode 48 | # strings. 49 | 50 | # Versions 2.x of Python don't support Unicode in sys.argv on 51 | # Windows, with the underlying Windows API instead replacing multi-byte 52 | # characters with '?'. 53 | 54 | 55 | from ctypes import POINTER, byref, cdll, c_int, windll 56 | from ctypes.wintypes import LPCWSTR, LPWSTR 57 | 58 | GetCommandLineW = cdll.kernel32.GetCommandLineW 59 | GetCommandLineW.argtypes = [] 60 | GetCommandLineW.restype = LPCWSTR 61 | 62 | CommandLineToArgvW = windll.shell32.CommandLineToArgvW 63 | CommandLineToArgvW.argtypes = [LPCWSTR, POINTER(c_int)] 64 | CommandLineToArgvW.restype = POINTER(LPWSTR) 65 | 66 | cmd = GetCommandLineW() 67 | argc = c_int(0) 68 | argv = CommandLineToArgvW(cmd, byref(argc)) 69 | if argc.value > 0: 70 | # Remove Python executable and commands if present 71 | start = argc.value - len(sys.argv) 72 | return [argv[i] for i in 73 | xrange(start, argc.value)] 74 | # if we don't have any arguments at all, just pass back script name 75 | # this should never happen 76 | return [u"mobidedrm.py"] 77 | else: 78 | argvencoding = sys.stdin.encoding 79 | if argvencoding == None: 80 | argvencoding = "utf-8" 81 | return [arg if (type(arg) == unicode) else unicode(arg,argvencoding) for arg in sys.argv] 82 | 83 | import hashlib 84 | 85 | def SHA256(message): 86 | ctx = hashlib.sha256() 87 | ctx.update(message) 88 | return ctx.digest() 89 | 90 | def crc32(s): 91 | return (~binascii.crc32(s,-1))&0xFFFFFFFF 92 | 93 | letters = 'ABCDEFGHIJKLMNPQRSTUVWXYZ123456789' 94 | 95 | def checksumPid(s): 96 | crc = crc32(s) 97 | crc = crc ^ (crc >> 16) 98 | res = s 99 | l = len(letters) 100 | for i in (0,1): 101 | b = crc & 0xff 102 | pos = (b // l) ^ (b % l) 103 | res += letters[pos%l] 104 | crc >>= 8 105 | 106 | return res 107 | 108 | def pidFromSerial(s, l): 109 | crc = crc32(s) 110 | 111 | arr1 = [0]*l 112 | for i in xrange(len(s)): 113 | arr1[i%l] ^= ord(s[i]) 114 | 115 | crc_bytes = [crc >> 24 & 0xff, crc >> 16 & 0xff, crc >> 8 & 0xff, crc & 0xff] 116 | for i in xrange(l): 117 | arr1[i] ^= crc_bytes[i&3] 118 | 119 | pid = '' 120 | for i in xrange(l): 121 | b = arr1[i] & 0xff 122 | pid+=letters[(b >> 7) + ((b >> 5 & 3) ^ (b & 0x1f))] 123 | 124 | return pid 125 | 126 | def generatekeys(email, mac): 127 | keys = [] 128 | email = email.encode('utf-8').lower() 129 | mac = mac.encode('utf-8').lower() 130 | cleanmac = "".join(c if (c in "0123456789abcdef") else "" for c in mac) 131 | lowermac = cleanmac.lower() 132 | #print lowermac 133 | keyseed = lowermac + email.encode('utf-8') 134 | #print keyseed 135 | keysha256 = SHA256(keyseed) 136 | keybase64 = keysha256.encode('base64') 137 | #print keybase64 138 | cleankeybase64 = "".join(c if (c in "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") else "0" for c in keybase64) 139 | #print cleankeybase64 140 | pseudoudid = cleankeybase64[:40] 141 | #print pseudoudid 142 | keys.append(pidFromSerial(pseudoudid.encode("utf-8"),8)) 143 | return keys 144 | 145 | # interface for Python DeDRM 146 | # returns single key or multiple keys, depending on path or file passed in 147 | def getkey(email, mac, outpath): 148 | keys = generatekeys(email,mac) 149 | if len(keys) > 0: 150 | if not os.path.isdir(outpath): 151 | outfile = outpath 152 | with file(outfile, 'w') as keyfileout: 153 | keyfileout.write(keys[0]) 154 | print u"Saved a key to {0}".format(outfile) 155 | else: 156 | keycount = 0 157 | for key in keys: 158 | while True: 159 | keycount += 1 160 | outfile = os.path.join(outpath,u"kindleios{0:d}.pid".format(keycount)) 161 | if not os.path.exists(outfile): 162 | break 163 | with file(outfile, 'w') as keyfileout: 164 | keyfileout.write(key) 165 | print u"Saved a key to {0}".format(outfile) 166 | return True 167 | return False 168 | 169 | def usage(progname): 170 | print u"Generates the key for Kindle for iOS 3.1.1" 171 | print u"Requires email address of Amazon acccount" 172 | print u"And MAC address for iOS device’s wifi" 173 | print u"Outputs to a file or to stdout" 174 | print u"Usage:" 175 | print u" {0:s} [-h] []".format(progname) 176 | 177 | 178 | def cli_main(): 179 | sys.stdout=SafeUnbuffered(sys.stdout) 180 | sys.stderr=SafeUnbuffered(sys.stderr) 181 | argv=unicode_argv() 182 | progname = os.path.basename(argv[0]) 183 | print u"{0} v{1}\nCopyright © 2013 Apprentice Alf".format(progname,__version__) 184 | 185 | try: 186 | opts, args = getopt.getopt(argv[1:], "h") 187 | except getopt.GetoptError, err: 188 | print u"Error in options or arguments: {0}".format(err.args[0]) 189 | usage(progname) 190 | sys.exit(2) 191 | 192 | for o, a in opts: 193 | if o == "-h": 194 | usage(progname) 195 | sys.exit(0) 196 | 197 | 198 | if len(args) < 2 or len(args) > 3: 199 | usage(progname) 200 | sys.exit(2) 201 | 202 | if len(args) == 3: 203 | # save to the specified file or folder 204 | getkey(args[0],args[1],args[2]) 205 | else: 206 | keys = generatekeys(args[0],args[1]) 207 | for key in keys: 208 | print key 209 | 210 | return 0 211 | 212 | 213 | def gui_main(): 214 | try: 215 | import Tkinter 216 | import Tkconstants 217 | import tkMessageBox 218 | except: 219 | print "Tkinter not installed" 220 | return cli_main() 221 | 222 | class DecryptionDialog(Tkinter.Frame): 223 | def __init__(self, root): 224 | Tkinter.Frame.__init__(self, root, border=5) 225 | self.status = Tkinter.Label(self, text=u"Enter parameters") 226 | self.status.pack(fill=Tkconstants.X, expand=1) 227 | body = Tkinter.Frame(self) 228 | body.pack(fill=Tkconstants.X, expand=1) 229 | sticky = Tkconstants.E + Tkconstants.W 230 | body.grid_columnconfigure(1, weight=2) 231 | Tkinter.Label(body, text=u"Amazon email address").grid(row=0) 232 | self.email = Tkinter.Entry(body, width=40) 233 | self.email.grid(row=0, column=1, sticky=sticky) 234 | Tkinter.Label(body, text=u"iOS MAC address").grid(row=1) 235 | self.mac = Tkinter.Entry(body, width=40) 236 | self.mac.grid(row=1, column=1, sticky=sticky) 237 | buttons = Tkinter.Frame(self) 238 | buttons.pack() 239 | button = Tkinter.Button( 240 | buttons, text=u"Generate", width=10, command=self.generate) 241 | button.pack(side=Tkconstants.LEFT) 242 | Tkinter.Frame(buttons, width=10).pack(side=Tkconstants.LEFT) 243 | button = Tkinter.Button( 244 | buttons, text=u"Quit", width=10, command=self.quit) 245 | button.pack(side=Tkconstants.RIGHT) 246 | 247 | def generate(self): 248 | email = self.email.get() 249 | mac = self.mac.get() 250 | if not email: 251 | self.status['text'] = u"Email not specified" 252 | return 253 | if not mac: 254 | self.status['text'] = u"MAC not specified" 255 | return 256 | self.status['text'] = u"Generating..." 257 | try: 258 | keys = generatekeys(email, mac) 259 | except Exception, e: 260 | self.status['text'] = u"Error: (0}".format(e.args[0]) 261 | return 262 | self.status['text'] = ", ".join(key for key in keys) 263 | 264 | root = Tkinter.Tk() 265 | root.title(u"Kindle for iOS PID Generator v.{0}".format(__version__)) 266 | root.resizable(True, False) 267 | root.minsize(300, 0) 268 | DecryptionDialog(root).pack(fill=Tkconstants.X, expand=1) 269 | root.mainloop() 270 | return 0 271 | 272 | if __name__ == '__main__': 273 | if len(sys.argv) > 1: 274 | sys.exit(cli_main()) 275 | sys.exit(gui_main()) 276 | --------------------------------------------------------------------------------