From e31752e3347ca7cc867e1ced37f17c7cab8fb5fe Mon Sep 17 00:00:00 2001 From: Apprentice Harper Date: Sun, 4 Oct 2020 20:36:12 +0100 Subject: [PATCH] Mostly Mac fixes. mobidedrm.py now works, and k4mobidedrm for at least some input. kindlekey.py should be working too. But lots more changes and testing to do. --- DeDRM_plugin/androidkindlekey.py | 60 ++++---- DeDRM_plugin/convert2xml.py | 15 +- DeDRM_plugin/erdr2pml.py | 8 +- DeDRM_plugin/genbook.py | 15 +- DeDRM_plugin/ignobleepub.py | 6 +- DeDRM_plugin/ignoblekey.py | 6 +- DeDRM_plugin/ignoblekeyfetch.py | 22 ++- DeDRM_plugin/ignoblekeygen.py | 24 ++-- DeDRM_plugin/ignoblepdf.py | 13 +- DeDRM_plugin/ineptepub.py | 6 +- DeDRM_plugin/k4mobidedrm.py | 8 +- DeDRM_plugin/kfxdedrm.py | 9 +- DeDRM_plugin/kgenpids.py | 18 +-- DeDRM_plugin/kindlekey.py | 229 +++++++++++++++++-------------- DeDRM_plugin/mobidedrm.py | 13 +- DeDRM_plugin/topazextract.py | 11 +- DeDRM_plugin/zipfix.py | 5 +- 17 files changed, 248 insertions(+), 220 deletions(-) diff --git a/DeDRM_plugin/androidkindlekey.py b/DeDRM_plugin/androidkindlekey.py index 4759e1b..dcd4d04 100644 --- a/DeDRM_plugin/androidkindlekey.py +++ b/DeDRM_plugin/androidkindlekey.py @@ -95,10 +95,8 @@ def unicode_argv(): # this should never happen return ["kindlekey.py"] else: - argvencoding = sys.stdin.encoding - if argvencoding == None: - argvencoding = "utf-8" - return argv + argvencoding = sys.stdin.encoding or "utf-8" + return [arg if isinstance(arg, str) else str(arg, argvencoding) for arg in sys.argv] class DrmException(Exception): pass @@ -336,7 +334,7 @@ def cli_main(): sys.stderr=SafeUnbuffered(sys.stderr) argv=unicode_argv() progname = os.path.basename(argv[0]) - print("{0} v{1}\nCopyright © 2010-2015 Thom, some_updates, Apprentice Alf and Apprentice Harper".format(progname,__version__)) + print("{0} v{1}\nCopyright © 2010-2020 Thom, Apprentice Harper et al.".format(progname,__version__)) try: opts, args = getopt.getopt(argv[1:], "hb:") @@ -386,48 +384,48 @@ def cli_main(): def gui_main(): try: - import Tkinter - import Tkconstants - import tkMessageBox - import tkFileDialog + import tkinter + import tkinter.constants + import tkinter.messagebox + import tkinter.filedialog except: - print("Tkinter not installed") + print("tkinter not installed") return cli_main() - class DecryptionDialog(Tkinter.Frame): + class DecryptionDialog(tkinter.Frame): def __init__(self, root): - Tkinter.Frame.__init__(self, root, border=5) - self.status = Tkinter.Label(self, text="Select backup.ab file") - self.status.pack(fill=Tkconstants.X, expand=1) - body = Tkinter.Frame(self) - body.pack(fill=Tkconstants.X, expand=1) - sticky = Tkconstants.E + Tkconstants.W + tkinter.Frame.__init__(self, root, border=5) + self.status = tkinter.Label(self, text="Select backup.ab file") + self.status.pack(fill=tkinter.constants.X, expand=1) + body = tkinter.Frame(self) + body.pack(fill=tkinter.constants.X, expand=1) + sticky = tkinter.constants.E + tkinter.constants.W body.grid_columnconfigure(1, weight=2) - Tkinter.Label(body, text="Backup file").grid(row=0, column=0) - self.keypath = Tkinter.Entry(body, width=40) + tkinter.Label(body, text="Backup file").grid(row=0, column=0) + self.keypath = tkinter.Entry(body, width=40) self.keypath.grid(row=0, column=1, sticky=sticky) self.keypath.insert(2, "backup.ab") - button = Tkinter.Button(body, text="...", command=self.get_keypath) + button = tkinter.Button(body, text="...", command=self.get_keypath) button.grid(row=0, column=2) - buttons = Tkinter.Frame(self) + buttons = tkinter.Frame(self) buttons.pack() - button2 = Tkinter.Button( + button2 = tkinter.Button( buttons, text="Extract", width=10, command=self.generate) - button2.pack(side=Tkconstants.LEFT) - Tkinter.Frame(buttons, width=10).pack(side=Tkconstants.LEFT) - button3 = Tkinter.Button( + button2.pack(side=tkinter.constants.LEFT) + tkinter.Frame(buttons, width=10).pack(side=tkinter.constants.LEFT) + button3 = tkinter.Button( buttons, text="Quit", width=10, command=self.quit) - button3.pack(side=Tkconstants.RIGHT) + button3.pack(side=tkinter.constants.RIGHT) def get_keypath(self): - keypath = tkFileDialog.askopenfilename( + keypath = tkinter.filedialog.askopenfilename( parent=None, title="Select backup.ab file", defaultextension=".ab", filetypes=[('adb backup com.amazon.kindle', '.ab'), ('All Files', '.*')]) if keypath: keypath = os.path.normpath(keypath) - self.keypath.delete(0, Tkconstants.END) + self.keypath.delete(0, tkinter.constants.END) self.keypath.insert(0, keypath) return @@ -447,7 +445,7 @@ def gui_main(): with open(outfile, 'w') as keyfileout: keyfileout.write(key) success = True - tkMessageBox.showinfo(progname, "Key successfully retrieved to {0}".format(outfile)) + tkinter.messagebox.showinfo(progname, "Key successfully retrieved to {0}".format(outfile)) except Exception as e: self.status['text'] = "Error: {0}".format(e.args[0]) return @@ -455,11 +453,11 @@ def gui_main(): argv=unicode_argv() progpath, progname = os.path.split(argv[0]) - root = Tkinter.Tk() + root = tkinter.Tk() root.title("Kindle for Android Key Extraction v.{0}".format(__version__)) root.resizable(True, False) root.minsize(300, 0) - DecryptionDialog(root).pack(fill=Tkconstants.X, expand=1) + DecryptionDialog(root).pack(fill=tkinter.constants.X, expand=1) root.mainloop() return 0 diff --git a/DeDRM_plugin/convert2xml.py b/DeDRM_plugin/convert2xml.py index a0bf188..3249db5 100644 --- a/DeDRM_plugin/convert2xml.py +++ b/DeDRM_plugin/convert2xml.py @@ -5,18 +5,25 @@ # For use with Topaz Scripts Version 2.6 # Python 3, September 2020 -class Unbuffered: +# Wrap a stream so that output gets flushed immediately +# and also make sure that any unicode strings get +# encoded using "replace" before writing them. +class SafeUnbuffered: def __init__(self, stream): self.stream = stream + self.encoding = stream.encoding + if self.encoding == None: + self.encoding = "utf-8" def write(self, data): + if isinstance(data, str): + data = data.encode(self.encoding,"replace") self.stream.buffer.write(data) self.stream.buffer.flush() + def __getattr__(self, attr): return getattr(self.stream, attr) import sys -sys.stdout=Unbuffered(sys.stdout) - import csv import os import getopt @@ -834,6 +841,8 @@ def usage(): # def main(argv): + sys.stdout=SafeUnbuffered(sys.stdout) + sys.stderr=SafeUnbuffered(sys.stderr) dictFile = "" pageFile = "" debug = False diff --git a/DeDRM_plugin/erdr2pml.py b/DeDRM_plugin/erdr2pml.py index bd3eeff..6c65ac2 100644 --- a/DeDRM_plugin/erdr2pml.py +++ b/DeDRM_plugin/erdr2pml.py @@ -128,10 +128,8 @@ def unicode_argv(): # this should never happen return ["mobidedrm.py"] else: - argvencoding = sys.stdin.encoding - if argvencoding == None: - argvencoding = "utf-8" - return argv + argvencoding = sys.stdin.encoding or "utf-8" + return [arg if isinstance(arg, str) else str(arg, argvencoding) for arg in sys.argv] Des = None if iswindows: @@ -516,7 +514,7 @@ def decryptBook(infile, outpath, make_pmlz, user_key): # remove temporary directory shutil.rmtree(outdir, True) print("Output is {0}".format(pmlzname)) - else: + else: print("Output is in {0}".format(outdir)) print("done") except ValueError as e: diff --git a/DeDRM_plugin/genbook.py b/DeDRM_plugin/genbook.py index fdf3707..dca5697 100644 --- a/DeDRM_plugin/genbook.py +++ b/DeDRM_plugin/genbook.py @@ -4,18 +4,25 @@ # Python 3 for calibre 5.0 from __future__ import print_function -class Unbuffered: +# Wrap a stream so that output gets flushed immediately +# and also make sure that any unicode strings get +# encoded using "replace" before writing them. +class SafeUnbuffered: def __init__(self, stream): self.stream = stream + self.encoding = stream.encoding + if self.encoding == None: + self.encoding = "utf-8" def write(self, data): + if isinstance(data, str): + data = data.encode(self.encoding,"replace") self.stream.buffer.write(data) self.stream.buffer.flush() + def __getattr__(self, attr): return getattr(self.stream, attr) import sys -sys.stdout=Unbuffered(sys.stdout) - import csv import os import getopt @@ -687,6 +694,8 @@ def usage(): def main(argv): + sys.stdout=SafeUnbuffered(sys.stdout) + sys.stderr=SafeUnbuffered(sys.stderr) bookDir = '' if len(argv) == 0: argv = sys.argv diff --git a/DeDRM_plugin/ignobleepub.py b/DeDRM_plugin/ignobleepub.py index d10b209..66c1e99 100644 --- a/DeDRM_plugin/ignobleepub.py +++ b/DeDRM_plugin/ignobleepub.py @@ -95,10 +95,8 @@ def unicode_argv(): range(start, argc.value)] return ["ineptepub.py"] else: - argvencoding = sys.stdin.encoding - if argvencoding == None: - argvencoding = "utf-8" - return argv + argvencoding = sys.stdin.encoding or "utf-8" + return [arg if isinstance(arg, str) else str(arg, argvencoding) for arg in sys.argv] class IGNOBLEError(Exception): diff --git a/DeDRM_plugin/ignoblekey.py b/DeDRM_plugin/ignoblekey.py index b47a07a..ce3fe0c 100644 --- a/DeDRM_plugin/ignoblekey.py +++ b/DeDRM_plugin/ignoblekey.py @@ -83,10 +83,8 @@ def unicode_argv(): # this should never happen return ["ignoblekey.py"] else: - argvencoding = sys.stdin.encoding - if argvencoding == None: - argvencoding = "utf-8" - return argv + argvencoding = sys.stdin.encoding or "utf-8" + return [arg if isinstance(arg, str) else str(arg, argvencoding) for arg in sys.argv] class DrmException(Exception): pass diff --git a/DeDRM_plugin/ignoblekeyfetch.py b/DeDRM_plugin/ignoblekeyfetch.py index a844fd8..89e6d62 100644 --- a/DeDRM_plugin/ignoblekeyfetch.py +++ b/DeDRM_plugin/ignoblekeyfetch.py @@ -90,10 +90,8 @@ def unicode_argv(): # this should never happen return ["ignoblekeyfetch.py"] else: - argvencoding = sys.stdin.encoding - if argvencoding == None: - argvencoding = "utf-8" - return argv + argvencoding = sys.stdin.encoding or "utf-8" + return [arg if isinstance(arg, str) else str(arg, argvencoding) for arg in sys.argv] class IGNOBLEError(Exception): @@ -109,18 +107,17 @@ def fetch_key(email, password): import random random = "%030x" % random.randrange(16**30) - import urllib, urllib2, re + import urllib.parse, urllib.request, re # try the URL from nook for PC fetch_url = "https://cart4.barnesandnoble.com/services/service.aspx?Version=2&acctPassword=" - fetch_url += urllib.quote(password,'')+"&devID=PC_BN_2.5.6.9575_"+random+"&emailAddress=" - fetch_url += urllib.quote(email,"")+"&outFormat=5&schema=1&service=1&stage=deviceHashB" + fetch_url += urllib.parse.quote(password,'')+"&devID=PC_BN_2.5.6.9575_"+random+"&emailAddress=" + fetch_url += urllib.parse.quote(email,"")+"&outFormat=5&schema=1&service=1&stage=deviceHashB" #print fetch_url found = '' try: - req = urllib2.Request(fetch_url) - response = urllib2.urlopen(req) + response = urllib.request.urlopen(fetch_url) the_page = response.read() #print the_page found = re.search('ccHash>(.+?)(.+?)"\u007f": #print "swapping char "+str(i)+" ("+buffer[i]+")" buffer[i] = "\ufffd" @@ -985,7 +985,7 @@ if iswindows: found = True print('Found K4PC 1.25+ kinf2018 file: ' + kinfopath.encode('ascii','ignore')) kInfoFiles.append(kinfopath) - + # look for (K4PC 1.9.0 and later) .kinf2011 file kinfopath = path +'\\Amazon\\Kindle\\storage\\.kinf2011' if os.path.isfile(kinfopath): @@ -1023,28 +1023,28 @@ if iswindows: # database of keynames and values def getDBfromFile(kInfoFile): names = [\ - 'kindle.account.tokens',\ - 'kindle.cookie.item',\ - 'eulaVersionAccepted',\ - 'login_date',\ - 'kindle.token.item',\ - 'login',\ - 'kindle.key.item',\ - 'kindle.name.info',\ - 'kindle.device.info',\ - 'MazamaRandomNumber',\ - 'max_date',\ - 'SIGVERIF',\ - 'build_version',\ - 'SerialNumber',\ - 'UsernameHash',\ - 'kindle.directedid.info',\ - 'DSN',\ - 'kindle.accounttype.info',\ - 'krx.flashcardsplugin.data.encryption_key',\ - 'krx.notebookexportplugin.data.encryption_key',\ - 'proxy.http.password',\ - 'proxy.http.username' + b'kindle.account.tokens',\ + b'kindle.cookie.item',\ + b'eulaVersionAccepted',\ + b'login_date',\ + b'kindle.token.item',\ + b'login',\ + b'kindle.key.item',\ + b'kindle.name.info',\ + b'kindle.device.info',\ + b'MazamaRandomNumber',\ + b'max_date',\ + b'SIGVERIF',\ + b'build_version',\ + b'SerialNumber',\ + b'UsernameHash',\ + b'kindle.directedid.info',\ + b'DSN',\ + b'kindle.accounttype.info',\ + b'krx.flashcardsplugin.data.encryption_key',\ + b'krx.notebookexportplugin.data.encryption_key',\ + b'proxy.http.password',\ + b'proxy.http.username' ] DB = {} with open(kInfoFile, 'rb') as infoReader: @@ -1053,7 +1053,7 @@ if iswindows: # the .kinf file uses "/" to separate it into records # so remove the trailing "/" to make it easy to use split data = data[:-1] - items = data.split('/') + items = data.split(b'/') # starts with an encoded and encrypted header blob headerblob = items.pop(0) @@ -1095,7 +1095,7 @@ if iswindows: # read and store in rcnt records of data # that make up the contents value edlst = [] - for i in xrange(rcnt): + for i in range(rcnt): item = items.pop(0) edlst.append(item) @@ -1276,8 +1276,8 @@ elif isosx: LibCrypto = _load_crypto() # Various character maps used to decrypt books. Probably supposed to act as obfuscation - charMap1 = 'n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M' - charMap2 = 'ZB0bYyc1xDdW2wEV3Ff7KkPpL8UuGA4gz-Tme9Nn_tHh5SvXCsIiR6rJjQaqlOoM' + charMap1 = b'n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M' + charMap2 = b'ZB0bYyc1xDdW2wEV3Ff7KkPpL8UuGA4gz-Tme9Nn_tHh5SvXCsIiR6rJjQaqlOoM' # For kinf approach of K4Mac 1.6.X or later # On K4PC charMap5 = 'AzB0bYyCeVvaZ3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_c1XxDdW2wE' @@ -1285,7 +1285,7 @@ elif isosx: charMap5 = charMap2 # new in K4M 1.9.X - testMap8 = 'YvaZ3FfUm9Nn_c1XuG4yCAzB0beVg-TtHh5SsIiR6rJjQdW2wEq7KkPpL8lOoMxD' + testMap8 = b'YvaZ3FfUm9Nn_c1XuG4yCAzB0beVg-TtHh5SsIiR6rJjQdW2wEq7KkPpL8lOoMxD' # uses a sub process to get the Hard Drive Serial Number using ioreg # returns serial numbers of all internal hard drive drives @@ -1299,11 +1299,11 @@ elif isosx: p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) out1, out2 = p.communicate() #print out1 - reslst = out1.split('\n') + reslst = out1.split(b'\n') cnt = len(reslst) - for j in xrange(cnt): + for j in range(cnt): resline = reslst[j] - pp = resline.find('\"Serial Number\" = \"') + pp = resline.find(b'\"Serial Number\" = \"') if pp >= 0: sernum = resline[pp+19:-1] sernums.append(sernum.strip()) @@ -1315,12 +1315,12 @@ elif isosx: cmdline = cmdline.encode(sys.getfilesystemencoding()) p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) out1, out2 = p.communicate() - reslst = out1.split('\n') + reslst = out1.split(b'\n') cnt = len(reslst) - for j in xrange(cnt): + for j in range(cnt): resline = reslst[j] - if resline.startswith('/dev'): - (devpart, mpath) = resline.split(' on ')[:2] + if resline.startswith(b'/dev'): + (devpart, mpath) = resline.split(b' on ')[:2] dpart = devpart[5:] names.append(dpart) return names @@ -1336,11 +1336,11 @@ elif isosx: p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) out1, out2 = p.communicate() #print out1 - reslst = out1.split('\n') + reslst = out1.split(b'\n') cnt = len(reslst) - for j in xrange(cnt): + for j in range(cnt): resline = reslst[j] - pp = resline.find('\"UUID\" = \"') + pp = resline.find(b'\"UUID\" = \"') if pp >= 0: uuidnum = resline[pp+10:-1] uuidnum = uuidnum.strip() @@ -1356,16 +1356,16 @@ elif isosx: cmdline = cmdline.encode(sys.getfilesystemencoding()) p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) out1, out2 = p.communicate() - reslst = out1.split('\n') + reslst = out1.split(b'\n') cnt = len(reslst) - for j in xrange(cnt): + for j in range(cnt): resline = reslst[j] - pp = resline.find('Ethernet Address: ') + pp = resline.find(b'Ethernet Address: ') if pp >= 0: #print resline macnum = resline[pp+18:] macnum = macnum.strip() - maclst = macnum.split(':') + maclst = macnum.split(b':') n = len(maclst) if n != 6: continue @@ -1373,7 +1373,7 @@ elif isosx: # now munge it up the way Kindle app does # by xoring it with 0xa5 and swapping elements 3 and 4 for i in range(6): - maclst[i] = int('0x' + maclst[i], 0) + maclst[i] = int(b'0x' + maclst[i], 0) mlst = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00] mlst[5] = maclst[5] ^ 0xa5 mlst[4] = maclst[3] ^ 0xa5 @@ -1381,7 +1381,7 @@ elif isosx: mlst[2] = maclst[2] ^ 0xa5 mlst[1] = maclst[1] ^ 0xa5 mlst[0] = maclst[0] ^ 0xa5 - macnum = '%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x' % (mlst[0], mlst[1], mlst[2], mlst[3], mlst[4], mlst[5]) + macnum = b'%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x' % (mlst[0], mlst[1], mlst[2], mlst[3], mlst[4], mlst[5]) #print 'munged mac', macnum macnums.append(macnum) return macnums @@ -1391,7 +1391,7 @@ elif isosx: def GetUserName(): username = os.getenv('USER') #print "Username:",username - return username + return username.encode('utf-8') def GetIDStrings(): # Return all possible ID Strings @@ -1400,7 +1400,7 @@ elif isosx: strings.extend(GetVolumesSerialNumbers()) strings.extend(GetDiskPartitionNames()) strings.extend(GetDiskPartitionUUIDs()) - strings.append('9999999999') + strings.append(b'9999999999') #print "ID Strings:\n",strings return strings @@ -1408,8 +1408,8 @@ elif isosx: # unprotect the new header blob in .kinf2011 # used in Kindle for Mac Version >= 1.9.0 def UnprotectHeaderData(encryptedData): - passwdData = 'header_key_data' - salt = 'HEADER.2011' + passwdData = b'header_key_data' + salt = b'HEADER.2011' iter = 0x80 keylen = 0x100 crp = LibCrypto() @@ -1424,7 +1424,7 @@ elif isosx: # implements an Pseudo Mac Version of Windows built-in Crypto routine class CryptUnprotectData(object): def __init__(self, entropy, IDString): - sp = GetUserName() + '+@#$%+' + IDString + sp = GetUserName() + b'+@#$%+' + IDString passwdData = encode(SHA256(sp),charMap2) salt = entropy self.crp = LibCrypto() @@ -1503,59 +1503,79 @@ elif isosx: # database of keynames and values def getDBfromFile(kInfoFile): names = [\ - 'kindle.account.tokens',\ - 'kindle.cookie.item',\ - 'eulaVersionAccepted',\ - 'login_date',\ - 'kindle.token.item',\ - 'login',\ - 'kindle.key.item',\ - 'kindle.name.info',\ - 'kindle.device.info',\ - 'MazamaRandomNumber',\ - 'max_date',\ - 'SIGVERIF',\ - 'build_version',\ - 'SerialNumber',\ - 'UsernameHash',\ - 'kindle.directedid.info',\ - 'DSN' - ] + b'kindle.account.tokens',\ + b'kindle.cookie.item',\ + b'eulaVersionAccepted',\ + b'login_date',\ + b'kindle.token.item',\ + b'login',\ + b'kindle.key.item',\ + b'kindle.name.info',\ + b'kindle.device.info',\ + b'MazamaRandomNumber',\ + b'max_date',\ + b'SIGVERIF',\ + b'build_version',\ + b'SerialNumber',\ + b'UsernameHash',\ + b'kindle.directedid.info',\ + b'DSN' + b'kindle.accounttype.info',\ + b'krx.flashcardsplugin.data.encryption_key',\ + b'krx.notebookexportplugin.data.encryption_key',\ + b'proxy.http.password',\ + b'proxy.http.username' + ] with open(kInfoFile, 'rb') as infoReader: filedata = infoReader.read() data = filedata[:-1] - items = data.split('/') + items = data.split(b'/') IDStrings = GetIDStrings() + print ("trying username ", GetUserName()) for IDString in IDStrings: - #print "trying IDString:",IDString + print ("trying IDString:",IDString) try: DB = {} - items = data.split('/') - + items = data.split(b'/') + # the headerblob is the encrypted information needed to build the entropy string headerblob = items.pop(0) + #print ("headerblob: ",headerblob) encryptedValue = decode(headerblob, charMap1) + #print ("encryptedvalue: ",encryptedValue) cleartext = UnprotectHeaderData(encryptedValue) + print ("cleartext: ",cleartext) # now extract the pieces in the same way - pattern = re.compile(r'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''', re.IGNORECASE) + pattern = re.compile(rb'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''', re.IGNORECASE) for m in re.finditer(pattern, cleartext): version = int(m.group(1)) build = m.group(2) guid = m.group(4) + print ("version",version) + print ("build",build) + print ("guid",guid,"\n") + if version == 5: # .kinf2011: identical to K4PC, except the build number gets multiplied - entropy = str(0x2df * int(build)) + guid + entropy = bytes(0x2df * int(build)) + guid cud = CryptUnprotectData(entropy,IDString) + print ("entropy",entropy) + print ("cud",cud) elif version == 6: # .kinf2018: identical to K4PC - salt = str(0x6d8 * int(build)) + guid - sp = GetUserName() + '+@#$%+' + IDString + salt = bytes(0x6d8 * int(build)) + guid + sp = GetUserName() + b'+@#$%+' + IDString passwd = encode(SHA256(sp), charMap5) key = LibCrypto().keyivgen(passwd, salt, 10000, 0x400)[:32] - # loop through the item records until all are processed + print ("salt",salt) + print ("sp",sp) + print ("passwd",passwd) + print ("key",key) + + # loop through the item records until all are processed while len(items) > 0: # get the first item record @@ -1564,7 +1584,7 @@ elif isosx: # the first 32 chars of the first record of a group # is the MD5 hash of the key name encoded by charMap5 keyhash = item[0:32] - keyname = 'unknown' + keyname = b'unknown' # unlike K4PC the keyhash is not used in generating entropy # entropy = SHA1(keyhash) + added_entropy @@ -1580,16 +1600,16 @@ elif isosx: # read and store in rcnt records of data # that make up the contents value edlst = [] - for i in xrange(rcnt): + for i in range(rcnt): item = items.pop(0) edlst.append(item) - keyname = 'unknown' + keyname = b'unknown' for name in names: if encodeHash(name,testMap8) == keyhash: keyname = name break - if keyname == 'unknown': + if keyname == b'unknown': keyname = keyhash # the testMap8 encoded contents data has had a length @@ -1603,7 +1623,7 @@ elif isosx: # (in other words split 'about' 2/3rds of the way through) # move first offsets chars to end to align for decode by testMap8 - encdata = ''.join(edlst) + encdata = b''.join(edlst) contlen = len(encdata) # now properly split and recombine @@ -1643,7 +1663,9 @@ elif isosx: if len(DB)>6: break - except: + + except Exception: + print (traceback.format_exc()) pass if len(DB)>6: # store values used in decryption @@ -1709,7 +1731,7 @@ def cli_main(): sys.stderr=SafeUnbuffered(sys.stderr) argv=unicode_argv() progname = os.path.basename(argv[0]) - print("{0} v{1}\nCopyright © 2010-2016 by some_updates, Apprentice Alf and Apprentice Harper".format(progname,__version__)) + print("{0} v{1}\nCopyright © 2010-2020 by some_updates, Apprentice Harper et al.".format(progname,__version__)) try: opts, args = getopt.getopt(argv[1:], "hk:") @@ -1800,6 +1822,7 @@ def gui_main(): return 0 if __name__ == '__main__': + print ("here") if len(sys.argv) > 1: sys.exit(cli_main()) sys.exit(gui_main()) diff --git a/DeDRM_plugin/mobidedrm.py b/DeDRM_plugin/mobidedrm.py index 05c7b07..fff0969 100644 --- a/DeDRM_plugin/mobidedrm.py +++ b/DeDRM_plugin/mobidedrm.py @@ -137,10 +137,8 @@ def unicode_argv(): # this should never happen return ["mobidedrm.py"] else: - argvencoding = sys.stdin.encoding - if argvencoding == None: - argvencoding = 'utf-8' - return sys.argv + argvencoding = sys.stdin.encoding or "utf-8" + return [arg if isinstance(arg, str) else str(arg, argvencoding) for arg in sys.argv] class DrmException(Exception): @@ -246,7 +244,7 @@ class MobiBook: pass def __init__(self, infile): - print("MobiDeDrm v{0:s}.\nCopyright © 2008-2017 The Dark Reverser, Apprentice Harper et al.".format(__version__)) + print("MobiDeDrm v{0:s}.\nCopyright © 2008-2020 The Dark Reverser, Apprentice Harper et al.".format(__version__)) try: from alfcrypto import Pukall_Cipher @@ -522,7 +520,7 @@ def cli_main(): argv=unicode_argv() progname = os.path.basename(argv[0]) if len(argv)<3 or len(argv)>4: - print("MobiDeDrm v{0:s}.\nCopyright © 2008-2017 The Dark Reverser, Apprentice Harper et al.".format(__version__)) + print("MobiDeDrm v{0:s}.\nCopyright © 2008-2020 The Dark Reverser, Apprentice Harper et al.".format(__version__)) print("Removes protection from Kindle/Mobipocket, Kindle/KF8 and Kindle/Print Replica ebooks") print("Usage:") print(" {0} []".format(progname)) @@ -531,7 +529,8 @@ def cli_main(): infile = argv[1] outfile = argv[2] if len(argv) == 4: - pidlist = argv[3].split(',') + # convert from unicode to bytearray before splitting. + pidlist = argv[3].encode('utf-8').split(b',') else: pidlist = [] try: diff --git a/DeDRM_plugin/topazextract.py b/DeDRM_plugin/topazextract.py index e1b97e0..f56626b 100644 --- a/DeDRM_plugin/topazextract.py +++ b/DeDRM_plugin/topazextract.py @@ -18,7 +18,10 @@ import zlib, zipfile, tempfile, shutil import traceback from struct import pack from struct import unpack -from calibre_plugins.dedrm.alfcrypto import Topaz_Cipher +try: + from calibre_plugins.dedrm.alfcrypto import Topaz_Cipher +except: + from alfcrypto import Topaz_Cipher class SafeUnbuffered: def __init__(self, stream): @@ -70,10 +73,8 @@ def unicode_argv(): # this should never happen return ["mobidedrm.py"] else: - argvencoding = sys.stdin.encoding - if argvencoding == None: - argvencoding = 'utf-8' - return argv + argvencoding = sys.stdin.encoding or "utf-8" + return [arg if isinstance(arg, str) else str(arg, argvencoding) for arg in sys.argv] #global switch debug = False diff --git a/DeDRM_plugin/zipfix.py b/DeDRM_plugin/zipfix.py index 9745495..fb6558c 100644 --- a/DeDRM_plugin/zipfix.py +++ b/DeDRM_plugin/zipfix.py @@ -22,7 +22,10 @@ __version__ = "1.1" import sys import zlib -import calibre_plugins.dedrm.zipfilerugged as zipfilerugged +try: + import zipfilerugged +except: + import calibre_plugins.dedrm.zipfilerugged as zipfilerugged import os import os.path import getopt