tools v5.2

This commit is contained in:
Apprentice Alf
2012-09-09 01:45:24 +01:00
parent 0812438b9d
commit f3f02adc98
75 changed files with 2556 additions and 1092 deletions

View File

@@ -1,35 +1,29 @@
ReadMe_DeDRM_vX.X_WinApp
ReadMe_DeDRM_v5.2_WinApp
-----------------------
DeDRM_vX.X_WinApp is a pure python drag and drop application that allows users to drag and drop ebooks or folders of ebooks onto the DeDRM_Drop_Target to have the DRM removed. It repackages the"tools" python software in one easy to use program that remembers preferences and settings.
DeDRM_v5.2_WinApp is a pure python drag and drop application that allows users to drag and drop ebooks or folders of ebooks onto the DeDRM_Drop_Target to have the DRM removed. It repackages the"tools" python software in one easy to use program that remembers preferences and settings.
It should work out of the box with Kindle for PC ebooks and Adobe Adept epub and pdf ebooks.
To remove the DRM from standalone Kindle ebooks, eReader pdb ebooks, Barnes and Noble epubs, and Mobipocket ebooks requires the user to double-click the DeDRM_Drop_Target and set some additional Preferences including:
Kindle 16 digit Serial Number
Barnes & Noble key files (bnepubkey.b64)
eReader Social DRM: (Name:Last 8 digits of CC number)
MobiPocket, Kindle for iPhone/iPad/iPodTouch 10 digit PID
eInk Kindle: 16 digit Serial Number
Barnes & Noble: key file (bnepubkey.b64)
eReader Social DRM: Name:Last 8 digits of CC number
MobiPocket: 10 digit PID
Once these preferences have been set, the user can simply drag and drop ebooks onto the DeDRM_Drop_Target to remove the DRM.
This program requires that the proper 32 bit version of Python 2.X (tested with Python 2.5 through Python 2.7) and PyCrypto be installed on your computer before it will work. See below for where to get theese programs for Windows.
Installation
------------
1. From tools_vX.X\DeDRM_Applications\, right click on DeDRM_v_X.X_WinApp.zip and fully Extract its contents.
1. In tools_v5.2\DeDRM_Applications\Windows, right click on DeDRM_5.2_Win.zip and fully extract its contents using "Extract All...", saving to your "My Documents" folder.
2. Move the resulting DeDRM_vX.X_WinApp folder to whereever you keep you other programs.
(I typically use an "Applications" folder inside of my home directory)
3. Open the folder, and create a short-cut to DeDRM_Drop_Target and move that short-cut to your Desktop.
4. To set the preferences simply double-click on your just created short-cut.
2. Open the DeDRM_5.2_Win folder you've just created, and make a short-cut of the DeDRM_Drop_Target.bat file (right-click/Create Shortcut). Drag the shortcut file onto your Desktop.
3. To set the preferences simply double-click on your just created short-cut.
If you already have a correct version of Python and PyCrypto installed and in your path, you are ready to go!

View File

@@ -21,7 +21,7 @@ import re
import simpleprefs
__version__ = '5.0'
__version__ = '5.2'
class DrmException(Exception):
pass
@@ -38,7 +38,7 @@ class MainApp(Tk):
['serials', 'seriallist.txt'],
['sdrms' , 'sdrmlist.txt' ],
['outdir' , 'outdir.txt' ]]
self.po = simpleprefs.SimplePrefs('DeDRM',description)
self.po = simpleprefs.SimplePrefs("DeDRM",description)
if self.dnd:
self.cd = ConvDialog(self)
prefs = self.getPreferences()
@@ -95,7 +95,7 @@ class PrefsDialog(Toplevel):
Toplevel.__init__(self, mainapp)
self.withdraw()
self.protocol("WM_DELETE_WINDOW", self.withdraw)
self.title("DeDRM")
self.title("DeDRM " + __version__)
self.prefs_array = prefs_array
self.status = Tkinter.Label(self, text='Setting Preferences')
self.status.pack(fill=Tkconstants.X, expand=1)
@@ -566,6 +566,7 @@ def main(argv=sys.argv):
infilelst = argv[1:]
filenames = []
for infile in infilelst:
infile = infile.decode(sys.getfilesystemencoding())
print infile
infile = infile.replace('"','')
infile = os.path.abspath(infile)

View File

@@ -0,0 +1,59 @@
from PyQt4.Qt import QWidget, QVBoxLayout, QLabel, QLineEdit
from calibre.utils.config import JSONConfig
# This is where all preferences for this plugin will be stored
# You should always prefix your config file name with plugins/,
# so as to ensure you dont accidentally clobber a calibre config file
prefs = JSONConfig('plugins/K4MobiDeDRM')
# Set defaults
prefs.defaults['pids'] = ""
prefs.defaults['serials'] = ""
prefs.defaults['WINEPREFIX'] = None
class ConfigWidget(QWidget):
def __init__(self):
QWidget.__init__(self)
self.l = QVBoxLayout()
self.setLayout(self.l)
self.serialLabel = QLabel('Kindle Serial numbers (separate with commas, no spaces)')
self.l.addWidget(self.serialLabel)
self.serials = QLineEdit(self)
self.serials.setText(prefs['serials'])
self.l.addWidget(self.serials)
self.serialLabel.setBuddy(self.serials)
self.pidLabel = QLabel('Mobipocket PIDs (separate with commas, no spaces)')
self.l.addWidget(self.pidLabel)
self.pids = QLineEdit(self)
self.pids.setText(prefs['pids'])
self.l.addWidget(self.pids)
self.pidLabel.setBuddy(self.serials)
self.wpLabel = QLabel('For Linux only: WINEPREFIX (enter absolute path)')
self.l.addWidget(self.wpLabel)
self.wineprefix = QLineEdit(self)
wineprefix = prefs['WINEPREFIX']
if wineprefix is not None:
self.wineprefix.setText(wineprefix)
else:
self.wineprefix.setText('')
self.l.addWidget(self.wineprefix)
self.wpLabel.setBuddy(self.wineprefix)
def save_settings(self):
prefs['pids'] = str(self.pids.text())
prefs['serials'] = str(self.serials.text())
winepref=str(self.wineprefix.text())
if winepref.strip() != '':
prefs['WINEPREFIX'] = winepref
else:
prefs['WINEPREFIX'] = None

View File

@@ -214,6 +214,7 @@ class PageParser(object):
'links.title' : (1, 'text', 0, 0),
'links.href' : (1, 'text', 0, 0),
'links.type' : (1, 'text', 0, 0),
'links.id' : (1, 'number', 0, 0),
'paraCont' : (0, 'number', 1, 1),
'paraCont.rootID' : (1, 'number', 0, 0),
@@ -239,6 +240,7 @@ class PageParser(object):
'group' : (1, 'snippets', 1, 0),
'group.type' : (1, 'scalar_text', 0, 0),
'group._tag' : (1, 'scalar_text', 0, 0),
'group.orientation': (1, 'scalar_text', 0, 0),
'region' : (1, 'snippets', 1, 0),
'region.type' : (1, 'scalar_text', 0, 0),
@@ -246,7 +248,7 @@ class PageParser(object):
'region.y' : (1, 'scalar_number', 0, 0),
'region.h' : (1, 'scalar_number', 0, 0),
'region.w' : (1, 'scalar_number', 0, 0),
'region.orientation' : (1, 'scalar_number', 0, 0),
'region.orientation' : (1, 'scalar_text', 0, 0),
'empty_text_region' : (1, 'snippets', 1, 0),

View File

@@ -0,0 +1,77 @@
#!/usr/bin/python
#
# This is a python script. You need a Python interpreter to run it.
# For example, ActiveState Python, which exists for windows.
#
# Changelog
# 1.00 - Initial version
__version__ = '1.00'
import sys
class Unbuffered:
def __init__(self, stream):
self.stream = stream
def write(self, data):
self.stream.write(data)
self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)
sys.stdout=Unbuffered(sys.stdout)
import os
import struct
import binascii
import kgenpids
import topazextract
import mobidedrm
from alfcrypto import Pukall_Cipher
class DrmException(Exception):
pass
def getK4PCpids(path_to_ebook):
# Return Kindle4PC PIDs. Assumes that the caller checked that we are not on Linux, which will raise an exception
mobi = True
magic3 = file(path_to_ebook,'rb').read(3)
if magic3 == 'TPZ':
mobi = False
if mobi:
mb = mobidedrm.MobiBook(path_to_ebook,False)
else:
mb = topazextract.TopazBook(path_to_ebook)
md1, md2 = mb.getPIDMetaInfo()
return kgenpids.getPidList(md1, md2, True, [], [], [])
def main(argv=sys.argv):
print ('getk4pcpids.py v%(__version__)s. '
'Copyright 2012 Apprentic Alf' % globals())
if len(argv)<2 or len(argv)>3:
print "Gets the possible book-specific PIDs from K4PC for a particular book"
print "Usage:"
print " %s <bookfile> [<outfile>]" % sys.argv[0]
return 1
else:
infile = argv[1]
try:
pidlist = getK4PCpids(infile)
except DrmException, e:
print "Error: %s" % e
return 1
pidstring = ','.join(pidlist)
print "Possible PIDs are: ", pidstring
if len(argv) is 3:
outfile = argv[2]
file(outfile, 'w').write(pidstring)
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -1,5 +1,5 @@
#! /usr/bin/env python
# ineptpdf.pyw, version 7.9
# ineptpdf.pyw, version 7.11
from __future__ import with_statement
@@ -34,6 +34,8 @@ from __future__ import with_statement
# 7.7 - On Windows try PyCrypto first and OpenSSL next
# 7.8 - Modify interface to allow use of import
# 7.9 - Bug fix for some session key errors when len(bookkey) > length required
# 7.10 - Various tweaks to fix minor problems.
# 7.11 - More tweaks to fix minor problems.
"""
Decrypts Adobe ADEPT-encrypted PDF files.
@@ -2200,11 +2202,19 @@ class DecryptionDialog(Tkinter.Frame):
def decryptBook(keypath, inpath, outpath):
with open(inpath, 'rb') as inf:
serializer = PDFSerializer(inf, keypath)
try:
serializer = PDFSerializer(inf, keypath)
except:
print "Error serializing pdf. Probably wrong key."
return 1
# hope this will fix the 'bad file descriptor' problem
with open(outpath, 'wb') as outf:
# help construct to make sure the method runs to the end
serializer.dump(outf)
try:
serializer.dump(outf)
except:
print "error writing pdf."
return 1
return 0

View File

@@ -17,7 +17,7 @@ from __future__ import with_statement
# and many many others
__version__ = '4.2'
__version__ = '4.4'
class Unbuffered:
def __init__(self, stream):
@@ -58,7 +58,7 @@ else:
# borrowed from calibre from calibre/src/calibre/__init__.py
# added in removal of non-printing chars
# and removal of . at start
# convert spaces to underscores
# convert underscores to spaces (we're OK with spaces in file names)
def cleanup_name(name):
_filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]')
substitute='_'
@@ -73,7 +73,7 @@ def cleanup_name(name):
# Mac and Unix don't like file names that begin with a full stop
if len(one) > 0 and one[0] == '.':
one = substitute+one[1:]
one = one.replace(' ','_')
one = one.replace('_',' ')
return one
def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
@@ -99,11 +99,20 @@ def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
title = mb.getBookTitle()
print "Processing Book: ", title
filenametitle = cleanup_name(title)
outfilename = bookname
if len(outfilename)<=8 or len(filenametitle)<=8:
outfilename = outfilename + "_" + filenametitle
elif outfilename[:8] != filenametitle[:8]:
outfilename = outfilename[:8] + "_" + filenametitle
outfilename = cleanup_name(bookname)
# generate 'sensible' filename, that will sort with the original name,
# but is close to the name from the file.
outlength = len(outfilename)
comparelength = min(8,min(outlength,len(filenametitle)))
copylength = min(max(outfilename.find(' '),8),len(outfilename))
if outlength==0:
outfilename = filenametitle
elif comparelength > 0:
if outfilename[:comparelength] == filenametitle[:comparelength]:
outfilename = filenametitle
else:
outfilename = outfilename[:copylength] + " " + filenametitle
# avoid excessively long file names
if len(outfilename)>150:

View File

@@ -40,7 +40,7 @@ def _load_crypto_libcrypto():
#
# int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
#
# note: the ivec string, and output buffer are mutable
# note: the ivec string, and output buffer are both mutable
# void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
# const unsigned long length, const AES_KEY *key, unsigned char *ivec, const int enc);
@@ -385,17 +385,22 @@ def GetIDString():
if isNewInstall():
mungedmac = GetMACAddressMunged()
if len(mungedmac) > 7:
print('Using Munged MAC Address for ID: '+mungedmac)
return mungedmac
sernum = GetVolumeSerialNumber()
if len(sernum) > 7:
print('Using Volume Serial Number for ID: '+sernum)
return sernum
diskpart = GetUserHomeAppSupKindleDirParitionName()
uuidnum = GetDiskPartitionUUID(diskpart)
if len(uuidnum) > 7:
print('Using Disk Partition UUID for ID: '+uuidnum)
return uuidnum
mungedmac = GetMACAddressMunged()
if len(mungedmac) > 7:
print('Using Munged MAC Address for ID: '+mungedmac)
return mungedmac
print('Using Fixed constant 9999999999 for ID.')
return '9999999999'
@@ -498,6 +503,7 @@ def getKindleInfoFiles(kInfoFiles):
for resline in reslst:
if os.path.isfile(resline):
kInfoFiles.append(resline)
print('Found K4Mac kindle-info file: ' + resline)
found = True
# add any .rainier*-kinf files
cmdline = 'find "' + home + '/Library/Application Support" -name ".rainier*-kinf"'
@@ -508,6 +514,7 @@ def getKindleInfoFiles(kInfoFiles):
for resline in reslst:
if os.path.isfile(resline):
kInfoFiles.append(resline)
print('Found k4Mac kinf file: ' + resline)
found = True
# add any .kinf2011 files
cmdline = 'find "' + home + '/Library/Application Support" -name ".kinf2011"'
@@ -518,9 +525,10 @@ def getKindleInfoFiles(kInfoFiles):
for resline in reslst:
if os.path.isfile(resline):
kInfoFiles.append(resline)
print('Found k4Mac kinf2011 file: ' + resline)
found = True
if not found:
print('No kindle-info files have been found.')
print('No k4Mac kindle-info/kinf/kinf2011 files have been found.')
return kInfoFiles
# determine type of kindle info provided and return a

View File

@@ -151,7 +151,9 @@ def GetVolumeSerialNumber():
GetVolumeSerialNumber = GetVolumeSerialNumber()
def GetIDString():
return GetVolumeSerialNumber()
vsn = GetVolumeSerialNumber()
print('Using Volume Serial Number for ID: '+vsn)
return vsn
def getLastError():
GetLastError = kernel32.GetLastError
@@ -210,37 +212,40 @@ def getKindleInfoFiles(kInfoFiles):
if 'LOCALAPPDATA' in os.environ.keys():
path = os.environ['LOCALAPPDATA']
print "searching for kinfoFiles in ", path
print('searching for kinfoFiles in ' + path)
found = False
# first look for older kindle-info files
kinfopath = path +'\\Amazon\\Kindle For PC\\{AMAwzsaPaaZAzmZzZQzgZCAkZ3AjA_AY}\\kindle.info'
if not os.path.isfile(kinfopath):
print('No kindle.info files have not been found.')
else:
if os.path.isfile(kinfopath):
found = True
print('Found K4PC kindle.info file: ' + kinfopath)
kInfoFiles.append(kinfopath)
# now look for newer (K4PC 1.5.0 and later rainier.2.1.1.kinf file
kinfopath = path +'\\Amazon\\Kindle For PC\\storage\\rainier.2.1.1.kinf'
if not os.path.isfile(kinfopath):
print('No K4PC 1.5.X .kinf files have not been found.')
else:
if os.path.isfile(kinfopath):
found = True
print('Found K4PC 1.5.X kinf file: ' + kinfopath)
kInfoFiles.append(kinfopath)
# now look for even newer (K4PC 1.6.0 and later) rainier.2.1.1.kinf file
kinfopath = path +'\\Amazon\\Kindle\\storage\\rainier.2.1.1.kinf'
if not os.path.isfile(kinfopath):
print('No K4PC 1.6.X .kinf files have not been found.')
else:
if os.path.isfile(kinfopath):
found = True
print('Found K4PC 1.6.X kinf file: ' + kinfopath)
kInfoFiles.append(kinfopath)
# now look for even newer (K4PC 1.9.0 and later) .kinf2011 file
kinfopath = path +'\\Amazon\\Kindle\\storage\\.kinf2011'
if not os.path.isfile(kinfopath):
print('No K4PC 1.9.X .kinf files have not been found.')
else:
if os.path.isfile(kinfopath):
found = True
print('Found K4PC kinf2011 file: ' + kinfopath)
kInfoFiles.append(kinfopath)
if not found:
print('No K4PC kindle.info/kinf/kinf2011 files have been found.')
return kInfoFiles

View File

@@ -262,9 +262,15 @@ def getPidList(md1, md2, k4, pids, serials, kInfoFiles):
if k4:
kInfoFiles = getKindleInfoFiles(kInfoFiles)
for infoFile in kInfoFiles:
pidlst = getK4Pids(pidlst, md1, md2, infoFile)
try:
pidlst = getK4Pids(pidlst, md1, md2, infoFile)
except Exception, message:
print("Error getting PIDs from " + infoFile + ": " + message)
for serialnum in serials:
pidlst = getKindlePid(pidlst, md1, md2, serialnum)
try:
pidlst = getKindlePid(pidlst, md1, md2, serialnum)
except Exception, message:
print("Error getting PIDs from " + serialnum + ": " + message)
for pid in pids:
pidlst.append(pid)
return pidlst

View File

@@ -57,8 +57,11 @@
# 0.33 - Performance improvements for large files (concatenation)
# 0.34 - Performance improvements in decryption (libalfcrypto)
# 0.35 - add interface to get mobi_version
# 0.36 - fixed problem with TEXtREAd and getBookTitle interface
# 0.37 - Fixed double announcement for stand-alone operation
__version__ = '0.35'
__version__ = '0.37'
import sys
@@ -168,9 +171,10 @@ class MobiBook:
off = self.sections[section][0]
return self.data_file[off:endoff]
def __init__(self, infile):
print ('MobiDeDrm v%(__version__)s. '
'Copyright 2008-2011 The Dark Reverser et al.' % globals())
def __init__(self, infile, announce = True):
if announce:
print ('MobiDeDrm v%(__version__)s. '
'Copyright 2008-2012 The Dark Reverser et al.' % globals())
# initial sanity check on file
self.data_file = file(infile, 'rb').read()
@@ -198,6 +202,7 @@ class MobiBook:
print "Book has format: ", self.magic
self.extra_data_flags = 0
self.mobi_length = 0
self.mobi_codepage = 1252
self.mobi_version = -1
self.meta_array = {}
return
@@ -248,18 +253,19 @@ class MobiBook:
65001 : 'utf-8',
}
title = ''
if 503 in self.meta_array:
title = self.meta_array[503]
else :
toff, tlen = struct.unpack('>II', self.sect[0x54:0x5c])
tend = toff + tlen
title = self.sect[toff:tend]
codec = 'windows-1252'
if self.magic == 'BOOKMOBI':
if 503 in self.meta_array:
title = self.meta_array[503]
else:
toff, tlen = struct.unpack('>II', self.sect[0x54:0x5c])
tend = toff + tlen
title = self.sect[toff:tend]
if self.mobi_codepage in codec_map.keys():
codec = codec_map[self.mobi_codepage]
if title == '':
title = self.header[:32]
title = title.split("\0")[0]
codec = 'windows-1252'
if self.mobi_codepage in codec_map.keys():
codec = codec_map[self.mobi_codepage]
return unicode(title, codec).encode('utf-8')
def getPIDMetaInfo(self):
@@ -375,7 +381,7 @@ class MobiBook:
raise DrmException("Not yet initialised with PID. Must be opened with Mobipocket Reader first.")
found_key, pid = self.parseDRM(self.sect[drm_ptr:drm_ptr+drm_size], drm_count, goodpids)
if not found_key:
raise DrmException("No key found. Please report this failure for help.")
raise DrmException("No key found in " + str(len(goodpids)) + " keys tried. Please report this failure for help.")
# kill the drm keys
self.patchSection(0, "\0" * drm_size, drm_ptr)
# kill the drm pointers
@@ -411,26 +417,26 @@ class MobiBook:
print "done"
return
def getUnencryptedBook(infile,pid):
def getUnencryptedBook(infile,pid,announce=True):
if not os.path.isfile(infile):
raise DrmException('Input File Not Found')
book = MobiBook(infile)
book = MobiBook(infile,announce)
book.processBook([pid])
return book.mobi_data
def getUnencryptedBookWithList(infile,pidlist):
def getUnencryptedBookWithList(infile,pidlist,announce=True):
if not os.path.isfile(infile):
raise DrmException('Input File Not Found')
book = MobiBook(infile)
book = MobiBook(infile, announce)
book.processBook(pidlist)
return book.mobi_data
def main(argv=sys.argv):
print ('MobiDeDrm v%(__version__)s. '
'Copyright 2008-2011 The Dark Reverser et al.' % globals())
'Copyright 2008-2012 The Dark Reverser et al.' % globals())
if len(argv)<3 or len(argv)>4:
print "Removes protection from Kindle/Mobipocket and Kindle/Print Replica ebooks"
print "Removes protection from Kindle/Mobipocket, Kindle/KF8 and Kindle/Print Replica ebooks"
print "Usage:"
print " %s <infile> <outfile> [<Comma separated list of PIDs to try>]" % sys.argv[0]
return 1
@@ -442,7 +448,7 @@ def main(argv=sys.argv):
else:
pidlist = {}
try:
stripped_file = getUnencryptedBookWithList(infile, pidlist)
stripped_file = getUnencryptedBookWithList(infile, pidlist, False)
file(outfile, 'wb').write(stripped_file)
except DrmException, e:
print "Error: %s" % e

View File

@@ -164,6 +164,9 @@ class DocParser(object):
scale = self.pw
elif attr == 'line-space':
scale = self.fontsize * 2.0
if val == "":
val = 0
if not ((attr == 'hang') and (int(val) == 0)) :
pv = float(val)/scale

View File

@@ -31,11 +31,8 @@ class TpzDRMError(Exception):
# local support routines
if inCalibre:
from calibre_plugins.k4mobidedrm import kgenpids
from calibre_plugins.k4mobidedrm import genbook
else:
import kgenpids
import genbook
# recursive zip creation support routine
def zipUpDir(myzip, tdir, localname):
@@ -271,6 +268,11 @@ class TopazBook:
self.createBookDirectory()
self.extractFiles()
print "Successfully Extracted Topaz contents"
if inCalibre:
from calibre_plugins.k4mobidedrm import genbook
else:
import genbook
rv = genbook.generateBook(self.outdir, raw, fixedimage)
if rv == 0:
print "\nBook Successfully generated"
@@ -300,6 +302,11 @@ class TopazBook:
self.createBookDirectory()
self.extractFiles()
print "Successfully Extracted Topaz contents"
if inCalibre:
from calibre_plugins.k4mobidedrm import genbook
else:
import genbook
rv = genbook.generateBook(self.outdir, raw, fixedimage)
if rv == 0:
print "\nBook Successfully generated"