mirror of
https://github.com/noDRM/DeDRM_tools.git
synced 2025-01-12 19:34:44 +06:00
CMBDTC 2.0
This commit is contained in:
parent
3a83053af9
commit
40b326020b
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Comprehensive Mazama Book DRM with Topaz Cryptography V1.1
|
Comprehensive Mazama Book DRM with Topaz Cryptography V2.0
|
||||||
|
|
||||||
-----BEGIN PUBLIC KEY-----
|
-----BEGIN PUBLIC KEY-----
|
||||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdBHJ4CNc6DNFCw4MRCw4SWAK6
|
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdBHJ4CNc6DNFCw4MRCw4SWAK6
|
||||||
@ -44,6 +44,7 @@ global bookPayloadOffset
|
|||||||
global bookHeaderRecords
|
global bookHeaderRecords
|
||||||
global bookMetadata
|
global bookMetadata
|
||||||
global bookKey
|
global bookKey
|
||||||
|
global command
|
||||||
|
|
||||||
#
|
#
|
||||||
# Various character maps used to decrypt books. Probably supposed to act as obfuscation
|
# Various character maps used to decrypt books. Probably supposed to act as obfuscation
|
||||||
@ -262,7 +263,7 @@ def getKindleInfoValueForKey(key):
|
|||||||
return getKindleInfoValueForHash(encodeHash(key,charMap2))
|
return getKindleInfoValueForHash(encodeHash(key,charMap2))
|
||||||
|
|
||||||
#
|
#
|
||||||
# Get a 7 bit encoded number form the book file
|
# Get a 7 bit encoded number from the book file
|
||||||
#
|
#
|
||||||
|
|
||||||
def bookReadEncodedNumber():
|
def bookReadEncodedNumber():
|
||||||
@ -284,6 +285,32 @@ def bookReadEncodedNumber():
|
|||||||
data = -data
|
data = -data
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
#
|
||||||
|
# Encode a number in 7 bit format
|
||||||
|
#
|
||||||
|
|
||||||
|
def encodeNumber(number):
|
||||||
|
result = ""
|
||||||
|
negative = False
|
||||||
|
flag = 0
|
||||||
|
|
||||||
|
if number < 0 :
|
||||||
|
number = -number + 1
|
||||||
|
negative = True
|
||||||
|
|
||||||
|
while True:
|
||||||
|
byte = number & 0x7F
|
||||||
|
number = number >> 7
|
||||||
|
byte += flag
|
||||||
|
result += chr(byte)
|
||||||
|
flag = 0x80
|
||||||
|
if number == 0 : break
|
||||||
|
|
||||||
|
if negative:
|
||||||
|
result += chr(0xFF)
|
||||||
|
|
||||||
|
return result[::-1]
|
||||||
|
|
||||||
#
|
#
|
||||||
# Get a length prefixed string from the file
|
# Get a length prefixed string from the file
|
||||||
#
|
#
|
||||||
@ -292,6 +319,14 @@ def bookReadString():
|
|||||||
stringLength = bookReadEncodedNumber()
|
stringLength = bookReadEncodedNumber()
|
||||||
return unpack(str(stringLength)+"s",bookFile.read(stringLength))[0]
|
return unpack(str(stringLength)+"s",bookFile.read(stringLength))[0]
|
||||||
|
|
||||||
|
#
|
||||||
|
# Returns a length prefixed string
|
||||||
|
#
|
||||||
|
|
||||||
|
def lengthPrefixString(data):
|
||||||
|
return encodeNumber(len(data))+data
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Read and return the data of one header record at the current book file position [[offset,compressedLength,decompressedLength],...]
|
# Read and return the data of one header record at the current book file position [[offset,compressedLength,decompressedLength],...]
|
||||||
#
|
#
|
||||||
@ -584,6 +619,94 @@ def generateDevicePID(table,dsn,nbRoll):
|
|||||||
pidAscii += charMap4[index]
|
pidAscii += charMap4[index]
|
||||||
return pidAscii
|
return pidAscii
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create decrypted book payload
|
||||||
|
#
|
||||||
|
|
||||||
|
def createDecryptedPayload(payload):
|
||||||
|
|
||||||
|
# store data to be able to create the header later
|
||||||
|
headerData= []
|
||||||
|
currentOffset = 0
|
||||||
|
|
||||||
|
# Add social DRM to decrypted files
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = getKindleInfoValueForKey("kindle.name.info")+":"+ getKindleInfoValueForKey("login")
|
||||||
|
if payload!= None:
|
||||||
|
payload.write(lengthPrefixString("sdrm"))
|
||||||
|
payload.write(encodeNumber(0))
|
||||||
|
payload.write(data)
|
||||||
|
else:
|
||||||
|
currentOffset += len(lengthPrefixString("sdrm"))
|
||||||
|
currentOffset += len(encodeNumber(0))
|
||||||
|
currentOffset += len(data)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for headerRecord in bookHeaderRecords:
|
||||||
|
name = headerRecord
|
||||||
|
newRecord = []
|
||||||
|
# if you are reading this, you might want to uncomment the next line :-D
|
||||||
|
#if name != "dkey" :
|
||||||
|
|
||||||
|
for index in range (0,len(bookHeaderRecords[name])) :
|
||||||
|
offset = currentOffset
|
||||||
|
|
||||||
|
if payload != None:
|
||||||
|
# write tag
|
||||||
|
payload.write(lengthPrefixString(name))
|
||||||
|
# write data
|
||||||
|
payload.write(encodeNumber(index))
|
||||||
|
payload.write(getBookPayloadRecord(name, index))
|
||||||
|
|
||||||
|
else :
|
||||||
|
currentOffset += len(lengthPrefixString(name))
|
||||||
|
currentOffset += len(encodeNumber(index))
|
||||||
|
currentOffset += len(getBookPayloadRecord(name, index))
|
||||||
|
newRecord.append([offset,bookHeaderRecords[name][index][1],bookHeaderRecords[name][index][2]])
|
||||||
|
|
||||||
|
headerData.append([name,newRecord])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return headerData
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create decrypted book
|
||||||
|
#
|
||||||
|
|
||||||
|
def createDecryptedBook(outputFile):
|
||||||
|
outputFile = open(outputFile,"wb")
|
||||||
|
# Write the payload in a temporary file
|
||||||
|
headerData = createDecryptedPayload(None)
|
||||||
|
outputFile.write("TPZ0")
|
||||||
|
outputFile.write(encodeNumber(len(headerData)))
|
||||||
|
|
||||||
|
for header in headerData :
|
||||||
|
outputFile.write(chr(0x63))
|
||||||
|
outputFile.write(lengthPrefixString(header[0]))
|
||||||
|
outputFile.write(encodeNumber(len(header[1])))
|
||||||
|
for numbers in header[1] :
|
||||||
|
outputFile.write(encodeNumber(numbers[0]))
|
||||||
|
outputFile.write(encodeNumber(numbers[1]))
|
||||||
|
outputFile.write(encodeNumber(numbers[2]))
|
||||||
|
|
||||||
|
outputFile.write(chr(0x64))
|
||||||
|
createDecryptedPayload(outputFile)
|
||||||
|
outputFile.close()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set the command to execute by the programm according to cmdLine parameters
|
||||||
|
#
|
||||||
|
|
||||||
|
def setCommand(name) :
|
||||||
|
global command
|
||||||
|
if command != "" :
|
||||||
|
raise CMBDTCFatal("Invalid command line parameters")
|
||||||
|
else :
|
||||||
|
command = name
|
||||||
|
|
||||||
#
|
#
|
||||||
# Program usage
|
# Program usage
|
||||||
#
|
#
|
||||||
@ -592,10 +715,11 @@ def usage():
|
|||||||
print("\nUsage:")
|
print("\nUsage:")
|
||||||
print("\nCMBDTC.py [options] bookFileName\n")
|
print("\nCMBDTC.py [options] bookFileName\n")
|
||||||
print("-p Adds a PID to the list of PIDs that are tried to decrypt the book key (can be used several times)")
|
print("-p Adds a PID to the list of PIDs that are tried to decrypt the book key (can be used several times)")
|
||||||
|
print("-d Saves a decrypted copy of the book")
|
||||||
print("-r Prints or writes to disk a record indicated in the form name:index (e.g \"img:0\")")
|
print("-r Prints or writes to disk a record indicated in the form name:index (e.g \"img:0\")")
|
||||||
print("-o Output file name to write records")
|
print("-o Output file name to write records and decrypted books")
|
||||||
print("-v Verbose (can be used several times)")
|
print("-v Verbose (can be used several times)")
|
||||||
print("-i Print kindle.info database")
|
print("-i Prints kindle.info database")
|
||||||
|
|
||||||
#
|
#
|
||||||
# Main
|
# Main
|
||||||
@ -606,15 +730,17 @@ def main(argv=sys.argv):
|
|||||||
global bookMetadata
|
global bookMetadata
|
||||||
global bookKey
|
global bookKey
|
||||||
global bookFile
|
global bookFile
|
||||||
|
global command
|
||||||
|
|
||||||
progname = os.path.basename(argv[0])
|
progname = os.path.basename(argv[0])
|
||||||
|
|
||||||
verbose = 0
|
verbose = 0
|
||||||
printInfo = False
|
|
||||||
recordName = ""
|
recordName = ""
|
||||||
recordIndex = 0
|
recordIndex = 0
|
||||||
outputFile = ""
|
outputFile = ""
|
||||||
PIDs = []
|
PIDs = []
|
||||||
kindleDatabase = None
|
kindleDatabase = None
|
||||||
|
command = ""
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -633,13 +759,24 @@ def main(argv=sys.argv):
|
|||||||
if o == "-v":
|
if o == "-v":
|
||||||
verbose+=1
|
verbose+=1
|
||||||
if o == "-i":
|
if o == "-i":
|
||||||
printInfo = True
|
setCommand("printInfo")
|
||||||
if o =="-o":
|
if o =="-o":
|
||||||
|
if a == None :
|
||||||
|
raise CMBDTCFatal("Invalid parameter for -o")
|
||||||
outputFile = a
|
outputFile = a
|
||||||
if o =="-r":
|
if o =="-r":
|
||||||
recordName,recordIndex = a.split(':')
|
setCommand("printRecord")
|
||||||
|
try:
|
||||||
|
recordName,recordIndex = a.split(':')
|
||||||
|
except:
|
||||||
|
raise CMBDTCFatal("Invalid parameter for -r")
|
||||||
if o =="-p":
|
if o =="-p":
|
||||||
PIDs.append(a)
|
PIDs.append(a)
|
||||||
|
if o =="-d":
|
||||||
|
setCommand("doit")
|
||||||
|
|
||||||
|
if command == "" :
|
||||||
|
raise CMBDTCFatal("No action supplied on command line")
|
||||||
|
|
||||||
#
|
#
|
||||||
# Read the encrypted database
|
# Read the encrypted database
|
||||||
@ -652,7 +789,7 @@ def main(argv=sys.argv):
|
|||||||
print(message)
|
print(message)
|
||||||
|
|
||||||
if kindleDatabase != None :
|
if kindleDatabase != None :
|
||||||
if printInfo:
|
if command == "printInfo" :
|
||||||
printKindleInfo()
|
printKindleInfo()
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -736,10 +873,19 @@ def main(argv=sys.argv):
|
|||||||
if verbose > 0:
|
if verbose > 0:
|
||||||
print("Book key: " + bookKey.encode('hex'))
|
print("Book key: " + bookKey.encode('hex'))
|
||||||
|
|
||||||
if recordName != "" :
|
|
||||||
|
|
||||||
|
if command == "printRecord" :
|
||||||
extractBookPayloadRecord(recordName,int(recordIndex),outputFile)
|
extractBookPayloadRecord(recordName,int(recordIndex),outputFile)
|
||||||
if outputFile != "" and verbose>0 :
|
if outputFile != "" and verbose>0 :
|
||||||
print("Wrote record to file: "+outputFile)
|
print("Wrote record to file: "+outputFile)
|
||||||
|
elif command == "doit" :
|
||||||
|
if outputFile!="" :
|
||||||
|
createDecryptedBook(outputFile)
|
||||||
|
if verbose >0 :
|
||||||
|
print ("Decrypted book saved. Don't pirate!")
|
||||||
|
elif verbose > 0:
|
||||||
|
print("Output file name was not supplied.")
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user