diff options
author | Apprentice Alf <[email protected]> | 2013-10-02 19:59:40 +0100 |
---|---|---|
committer | Apprentice Alf <[email protected]> | 2015-03-07 21:10:52 +0000 |
commit | b1feca321df4804b0f178ce96c476a70b9016113 (patch) | |
tree | ae61124973b2a10e57ff85aa0c3e610ee007c78b /DeDRM_Windows_Application | |
parent | 74a4c894cb24cb2eeadbe2bf8afcba522e430bb3 (diff) |
tools v6.0.8
Diffstat (limited to 'DeDRM_Windows_Application')
10 files changed, 218 insertions, 16 deletions
diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_app.pyw b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_app.pyw index e73226b..7225b6d 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_app.pyw +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_app.pyw @@ -12,7 +12,7 @@ # 6.0.4 - Fix for other potential unicode problems # 6.0.5 - Fix typo -__version__ = '6.0.7' +__version__ = '6.0.8' import sys import os, os.path diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py index caed6e8..37d4cb1 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__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_Windows_Application/DeDRM_App/DeDRM_lib/lib/android.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/android.py new file mode 100644 index 0000000..ddb94f5 --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/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_Windows_Application/DeDRM_App/DeDRM_lib/lib/android_readme.txt b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/android_readme.txt new file mode 100644 index 0000000..9e7d035 --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/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_Windows_Application/DeDRM_App/DeDRM_lib/lib/flatxml2html.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/flatxml2html.py index 4d83368..991591b 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/flatxml2html.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/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_Windows_Application/DeDRM_App/DeDRM_lib/lib/k4mobidedrm.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/k4mobidedrm.py index 929ce57..504105b 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/k4mobidedrm.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/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_Windows_Application/DeDRM_App/DeDRM_lib/lib/kindlekey.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kindlekey.py index f58e973..8852769 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kindlekey.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/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_Windows_Application/DeDRM_App/DeDRM_lib/lib/mobidedrm.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/mobidedrm.py index 7b69edc..89cc695 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/mobidedrm.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/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_Windows_Application/DeDRM_App/DeDRM_lib/lib/stylexml2css.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/stylexml2css.py index c111850..daa108a 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/stylexml2css.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/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_Windows_Application/DeDRM_App/DeDRM_lib/lib/topazextract.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/topazextract.py index 97f6583..fb5eb7a 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/topazextract.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/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 |