summaryrefslogtreecommitdiffstats
path: root/DeDRM_Macintosh_Application
diff options
context:
space:
mode:
authorApprentice Alf <[email protected]>2013-10-02 19:59:40 +0100
committerApprentice Alf <[email protected]>2015-03-07 21:10:52 +0000
commitb1feca321df4804b0f178ce96c476a70b9016113 (patch)
treeae61124973b2a10e57ff85aa0c3e610ee007c78b /DeDRM_Macintosh_Application
parent74a4c894cb24cb2eeadbe2bf8afcba522e430bb3 (diff)
tools v6.0.8
Diffstat (limited to 'DeDRM_Macintosh_Application')
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist6
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py9
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/android.py157
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/android_readme.txt6
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/flatxml2html.py6
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mobidedrm.py11
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py32
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/mobidedrm.py2
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/stylexml2css.py7
-rw-r--r--DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/topazextract.py2
10 files changed, 220 insertions, 18 deletions
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist
index 9a030d4..cfd9fcc 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist
@@ -24,19 +24,19 @@
<key>CFBundleExecutable</key>
<string>droplet</string>
<key>CFBundleGetInfoString</key>
- <string>DeDRM AppleScript 6.0.7. Written 2010–2013 by Apprentice Alf and others.</string>
+ <string>DeDRM AppleScript 6.0.8. Written 2010–2013 by Apprentice Alf and others.</string>
<key>CFBundleIconFile</key>
<string>DeDRM</string>
<key>CFBundleIdentifier</key>
<string>com.apple.ScriptEditor.id.707CCCD5-0C6C-4BEB-B67C-B6E866ADE85A</string>
<key>CFBundleInfoDictionaryVersion</key>
- <string>6.0.7</string>
+ <string>6.0.8</string>
<key>CFBundleName</key>
<string>DeDRM</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>6.0.7</string>
+ <string>6.0.8</string>
<key>CFBundleSignature</key>
<string>dplt</string>
<key>LSRequiresCarbon</key>
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py
index caed6e8..37d4cb1 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py
@@ -31,14 +31,17 @@ __docformat__ = 'restructuredtext en'
# 6.0.3 - Fixes for Kindle for Mac and Windows non-ascii user names
# 6.0.4 - Fixes for stand-alone scripts and applications
# and pdb files in plugin and initial conversion of prefs.
+# 6.0.5 - Fix a key issue
# 6.0.6 - Fix up an incorrect function call
+# 6.0.7 - Error handling for incomplete PDF metadata
+# 6.0.8 - Fixes a Wine key issue and topaz support
"""
Decrypt DRMed ebooks.
"""
PLUGIN_NAME = u"DeDRM"
-PLUGIN_VERSION_TUPLE = (6, 0, 7)
+PLUGIN_VERSION_TUPLE = (6, 0, 8)
PLUGIN_VERSION = u".".join([unicode(str(x)) for x in PLUGIN_VERSION_TUPLE])
# Include an html helpfile in the plugin's zipfile with the following name.
RESOURCE_NAME = PLUGIN_NAME + '_Help.htm'
@@ -313,7 +316,7 @@ class DeDRM(FileTypePlugin):
from wineutils import WineGetKeys
scriptpath = os.path.join(self.alfdir,u"adobekey.py")
- defaultkeys = self.WineGetKeys(scriptpath, u".der",dedrmprefs['adobewineprefix'])
+ defaultkeys = WineGetKeys(scriptpath, u".der",dedrmprefs['adobewineprefix'])
except:
pass
@@ -391,7 +394,7 @@ class DeDRM(FileTypePlugin):
from wineutils import WineGetKeys
scriptpath = os.path.join(self.alfdir,u"kindlekey.py")
- defaultkeys = self.WineGetKeys(scriptpath, u".k4i",dedrmprefs['kindlewineprefix'])
+ defaultkeys = WineGetKeys(scriptpath, u".k4i",dedrmprefs['kindlewineprefix'])
except:
pass
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/android.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/android.py
new file mode 100644
index 0000000..ddb94f5
--- /dev/null
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/android.py
@@ -0,0 +1,157 @@
+#!/usr/bin/env python
+#fileencoding: utf-8
+
+import os
+import sys
+import zlib
+import tarfile
+from hashlib import md5
+from cStringIO import StringIO
+from binascii import a2b_hex, b2a_hex
+
+STORAGE = 'AmazonSecureStorage.xml'
+
+class AndroidObfuscation(object):
+ '''AndroidObfuscation
+ For the key, it's written in java, and run in android dalvikvm
+ '''
+
+ key = a2b_hex('0176e04c9408b1702d90be333fd53523')
+
+ def encrypt(self, plaintext):
+ cipher = self._get_cipher()
+ padding = len(self.key) - len(plaintext) % len(self.key)
+ plaintext += chr(padding) * padding
+ return b2a_hex(cipher.encrypt(plaintext))
+
+ def decrypt(self, ciphertext):
+ cipher = self._get_cipher()
+ plaintext = cipher.decrypt(a2b_hex(ciphertext))
+ return plaintext[:-ord(plaintext[-1])]
+
+ def _get_cipher(self):
+ try:
+ from Crypto.Cipher import AES
+ return AES.new(self.key)
+ except ImportError:
+ from aescbc import AES, noPadding
+ return AES(self.key, padding=noPadding())
+
+class AndroidObfuscationV2(AndroidObfuscation):
+ '''AndroidObfuscationV2
+ '''
+
+ count = 503
+ password = 'Thomsun was here!'
+
+ def __init__(self, salt):
+ key = self.password + salt
+ for _ in range(self.count):
+ key = md5(key).digest()
+ self.key = key[:8]
+ self.iv = key[8:16]
+
+ def _get_cipher(self):
+ try :
+ from Crypto.Cipher import DES
+ return DES.new(self.key, DES.MODE_CBC, self.iv)
+ except ImportError:
+ from python_des import Des, CBC
+ return Des(self.key, CBC, self.iv)
+
+def parse_preference(path):
+ ''' parse android's shared preference xml '''
+ storage = {}
+ read = open(path)
+ for line in read:
+ line = line.strip()
+ # <string name="key">value</string>
+ if line.startswith('<string name="'):
+ index = line.find('"', 14)
+ key = line[14:index]
+ value = line[index+2:-9]
+ storage[key] = value
+ read.close()
+ return storage
+
+def get_serials(path=None):
+ ''' get serials from android's shared preference xml '''
+ if path is None:
+ if not os.path.isfile(STORAGE):
+ if os.path.isfile("backup.ab"):
+ get_storage()
+ else:
+ return []
+ path = STORAGE
+
+ if not os.path.isfile(path):
+ return []
+
+ storage = parse_preference(path)
+ salt = storage.get('AmazonSaltKey')
+ if salt and len(salt) == 16:
+ sys.stdout.write('Using AndroidObfuscationV2\n')
+ obfuscation = AndroidObfuscationV2(a2b_hex(salt))
+ else:
+ sys.stdout.write('Using AndroidObfuscation\n')
+ obfuscation = AndroidObfuscation()
+
+ def get_value(key):
+ encrypted_key = obfuscation.encrypt(key)
+ encrypted_value = storage.get(encrypted_key)
+ if encrypted_value:
+ return obfuscation.decrypt(encrypted_value)
+ return ''
+
+ # also see getK4Pids in kgenpids.py
+ try:
+ dsnid = get_value('DsnId')
+ except:
+ sys.stderr.write('cannot get DsnId\n')
+ return []
+
+ try:
+ tokens = set(get_value('kindle.account.tokens').split(','))
+ except:
+ return [dsnid]
+
+ serials = []
+ for token in tokens:
+ if token:
+ serials.append('%s%s' % (dsnid, token))
+ serials.append(dsnid)
+ for token in tokens:
+ if token:
+ serials.append(token)
+ return serials
+
+def get_storage(path='backup.ab'):
+ '''get AmazonSecureStorage.xml from android backup.ab
+ backup.ab can be get using adb command:
+ shell> adb backup com.amazon.kindle
+ '''
+ output = None
+ read = open(path, 'rb')
+ head = read.read(24)
+ if head == 'ANDROID BACKUP\n1\n1\nnone\n':
+ output = StringIO(zlib.decompress(read.read()))
+ read.close()
+
+ if not output:
+ return False
+
+ tar = tarfile.open(fileobj=output)
+ for member in tar.getmembers():
+ if member.name.strip().endswith(STORAGE):
+ write = open(STORAGE, 'w')
+ write.write(tar.extractfile(member).read())
+ write.close()
+ break
+
+ return True
+
+__all__ = [ 'get_storage', 'get_serials', 'parse_preference',
+ 'AndroidObfuscation', 'AndroidObfuscationV2', 'STORAGE']
+
+if __name__ == '__main__':
+ print get_serials() \ No newline at end of file
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/android_readme.txt b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/android_readme.txt
new file mode 100644
index 0000000..9e7d035
--- /dev/null
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/android_readme.txt
@@ -0,0 +1,6 @@
+1.1 get AmazonSecureStorage.xml from /data/data/com.amazon.kindle/shared_prefs/AmazonSecureStorage.xml
+
+1.2 on android 4.0+, run `adb backup com.amazon.kindle` from PC will get backup.ab
+ now android.py can convert backup.ab to AmazonSecureStorage.xml
+
+2. run `k4mobidedrm.py -a AmazonSecureStorage.xml <infile> <outdir>'
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/flatxml2html.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/flatxml2html.py
index 4d83368..991591b 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/flatxml2html.py
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/flatxml2html.py
@@ -458,7 +458,11 @@ class DocParser(object):
(wtype, num) = pdesc[j]
if wtype == 'ocr' :
- word = self.ocrtext[num]
+ try:
+ word = self.ocrtext[num]
+ except:
+ word = ""
+
sep = ' '
if handle_links:
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mobidedrm.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mobidedrm.py
index 929ce57..504105b 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mobidedrm.py
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mobidedrm.py
@@ -80,10 +80,12 @@ if inCalibre:
from calibre_plugins.dedrm import mobidedrm
from calibre_plugins.dedrm import topazextract
from calibre_plugins.dedrm import kgenpids
+ from calibre_plugins.dedrm import android
else:
import mobidedrm
import topazextract
import kgenpids
+ import android
# Wrap a stream so that output gets flushed immediately
# and also make sure that any unicode strings get
@@ -273,7 +275,7 @@ def decryptBook(infile, outdir, kDatabaseFiles, serials, pids):
def usage(progname):
print u"Removes DRM protection from Mobipocket, Amazon KF8, Amazon Print Replica and Amazon Topaz ebooks"
print u"Usage:"
- print u" {0} [-k <kindle.k4i>] [-p <comma separated PIDs>] [-s <comma separated Kindle serial numbers>] <infile> <outdir>".format(progname)
+ print u" {0} [-k <kindle.k4i>] [-p <comma separated PIDs>] [-s <comma separated Kindle serial numbers>] [ -a <AmazonSecureStorage.xml> ] <infile> <outdir>".format(progname)
#
# Main
@@ -284,7 +286,7 @@ def cli_main():
print u"K4MobiDeDrm v{0}.\nCopyright © 2008-2013 The Dark Reverser et al.".format(__version__)
try:
- opts, args = getopt.getopt(argv[1:], "k:p:s:")
+ opts, args = getopt.getopt(argv[1:], "k:p:s:a:")
except getopt.GetoptError, err:
print u"Error in options or arguments: {0}".format(err.args[0])
usage(progname)
@@ -312,6 +314,11 @@ def cli_main():
if a == None :
raise DrmException("Invalid parameter for -s")
serials = a.split(',')
+ if o == '-a':
+ if a == None:
+ continue
+ serials.extend(android.get_serials(a))
+ serials.extend(android.get_serials())
# try with built in Kindle Info files if not on Linux
k4 = not sys.platform.startswith('linux')
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py
index f58e973..8852769 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py
@@ -19,6 +19,7 @@ from __future__ import with_statement
# 1.6 - Fixed a problem getting the disk serial numbers
# 1.7 - Work if TkInter is missing
# 1.8 - Fixes for Kindle for Mac, and non-ascii in Windows user names
+# 1.9 - Fixes for Unicode in Windows user names
"""
@@ -26,7 +27,7 @@ Retrieve Kindle for PC/Mac user key.
"""
__license__ = 'GPL v3'
-__version__ = '1.8'
+__version__ = '1.9'
import sys, os, re
from struct import pack, unpack, unpack_from
@@ -907,18 +908,34 @@ if iswindows:
return CryptUnprotectData
CryptUnprotectData = CryptUnprotectData()
+ # Returns Environmental Variables that contain unicode
+ def getEnvironmentVariable(name):
+ import ctypes
+ name = unicode(name) # make sure string argument is unicode
+ n = ctypes.windll.kernel32.GetEnvironmentVariableW(name, None, 0)
+ if n == 0:
+ return None
+ buf = ctypes.create_unicode_buffer(u'\0'*n)
+ ctypes.windll.kernel32.GetEnvironmentVariableW(name, buf, n)
+ return buf.value
# Locate all of the kindle-info style files and return as list
def getKindleInfoFiles():
kInfoFiles = []
# some 64 bit machines do not have the proper registry key for some reason
- # or the pythonn interface to the 32 vs 64 bit registry is broken
+ # or the python interface to the 32 vs 64 bit registry is broken
path = ""
if 'LOCALAPPDATA' in os.environ.keys():
- path = os.environ['LOCALAPPDATA']
+ # Python 2.x does not return unicode env. Use Python 3.x
+ path = winreg.ExpandEnvironmentStrings(u"%LOCALAPPDATA%")
+ # this is just another alternative.
+ # path = getEnvironmentVariable('LOCALAPPDATA')
+ if not os.path.isdir(path):
+ path = ""
else:
# User Shell Folders show take precedent over Shell Folders if present
try:
+ # this will still break
regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders\\")
path = winreg.QueryValueEx(regkey, 'Local AppData')[0]
if not os.path.isdir(path):
@@ -937,13 +954,14 @@ if iswindows:
if path == "":
print ('Could not find the folder in which to look for kinfoFiles.')
else:
- print('searching for kinfoFiles in ' + path)
+ # Probably not the best. To Fix (shouldn't ignore in encoding) or use utf-8
+ print(u'searching for kinfoFiles in ' + path.encode('ascii', 'ignore'))
# look for (K4PC 1.9.0 and later) .kinf2011 file
kinfopath = path +'\\Amazon\\Kindle\\storage\\.kinf2011'
if os.path.isfile(kinfopath):
found = True
- print('Found K4PC 1.9+ kinf2011 file: ' + kinfopath)
+ print('Found K4PC 1.9+ kinf2011 file: ' + kinfopath.encode('ascii','ignore'))
kInfoFiles.append(kinfopath)
# look for (K4PC 1.6.0 and later) rainier.2.1.1.kinf file
@@ -1142,7 +1160,7 @@ if iswindows:
cleartext = CryptUnprotectData(encryptedValue, entropy, 1)
DB[keyname] = cleartext
- if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB:
+ if 'kindle.account.tokens' in DB:
print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(GetIDString(), GetUserName().decode("latin-1"))
# store values used in decryption
DB['IDString'] = GetIDString()
@@ -1758,7 +1776,7 @@ elif isosx:
break
except:
pass
- if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB:
+ if 'kindle.account.tokens' in DB:
# store values used in decryption
print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(IDString, GetUserName())
DB['IDString'] = IDString
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/mobidedrm.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/mobidedrm.py
index 7b69edc..89cc695 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/mobidedrm.py
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/mobidedrm.py
@@ -156,6 +156,8 @@ def PC1(key, src, decryption=True):
return Pukall_Cipher().PC1(key,src,decryption)
except NameError:
pass
+ except TypeError:
+ pass
# use slow python version, since Pukall_Cipher didn't load
sum1 = 0;
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/stylexml2css.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/stylexml2css.py
index c111850..daa108a 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/stylexml2css.py
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/stylexml2css.py
@@ -178,7 +178,12 @@ class DocParser(object):
if val == "":
val = 0
- if not ((attr == 'hang') and (int(val) == 0)) :
+ if not ((attr == 'hang') and (int(val) == 0)):
+ try:
+ f = float(val)
+ except:
+ print "Warning: unrecognised val, ignoring"
+ val = 0
pv = float(val)/scale
cssargs[attr] = (self.attr_val_map[attr], pv)
keep = True
diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/topazextract.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/topazextract.py
index 97f6583..fb5eb7a 100644
--- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/topazextract.py
+++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/topazextract.py
@@ -356,7 +356,7 @@ class TopazBook:
self.setBookKey(bookKey)
self.createBookDirectory()
- self.extractFiles()
+ self.extractFiles()
print u"Successfully Extracted Topaz contents"
if inCalibre:
from calibre_plugins.dedrm import genbook