The ususal method of Preferences -> Plugins -> Load plugin from file.
16 |
17 |
18 | 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 | 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 | 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 | Click the OK button to save the PID. Or Cancel if you didn’t want to enter a PID.
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 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 | 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 | 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 | Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.
34 |
35 | 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 |
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 |
--------------------------------------------------------------------------------