First Applescript for calling mobidedrm python script

This commit is contained in:
Paul Durrant
2008-08-27 19:00:23 +01:00
committed by Apprentice Alf
parent 87630e2bd4
commit 1096e48342
10 changed files with 355 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>*</string>
</array>
<key>CFBundleTypeOSTypes</key>
<array>
<string>****</string>
</array>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>droplet</string>
<key>CFBundleIconFile</key>
<string>droplet</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Mobipocket Unlocker 4</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>dplt</string>
<key>LSRequiresCarbon</key>
<true/>
<key>WindowState</key>
<dict>
<key>name</key>
<string>ScriptWindowState</string>
<key>positionOfDivider</key>
<real>435</real>
<key>savedFrame</key>
<string>53 78 661 691 0 0 1280 778 </string>
<key>selectedTabView</key>
<string>result</string>
</dict>
</dict>
</plist>

View File

@@ -0,0 +1 @@
APPLdplt

View File

@@ -0,0 +1,186 @@
# This is a python script. You need a Python interpreter to run it.
# For example, ActiveState Python, which exists for windows.
#
# Changelog
# 0.01 - Initial version
# 0.02 - Huffdic compressed books were not properly decrypted
# 0.03 - fix 0.02 to work with all Mobipocket eBooks
# 0.04 - Wasn't checking MOBI header length
import sys,struct,binascii
class DrmException(Exception):
pass
#implementation of Pukall Cipher 1
def PC1(key, src, decryption=True):
sum1 = 0;
sum2 = 0;
keyXorVal = 0;
if len(key)!=16:
print "Bad key length!"
return None
wkey = []
for i in xrange(8):
wkey.append(ord(key[i*2])<<8 | ord(key[i*2+1]))
dst = ""
for i in xrange(len(src)):
temp1 = 0;
byteXorVal = 0;
for j in xrange(8):
temp1 ^= wkey[j]
sum2 = (sum2+j)*20021 + sum1
sum1 = (temp1*346)&0xFFFF
sum2 = (sum2+sum1)&0xFFFF
temp1 = (temp1*20021+1)&0xFFFF
byteXorVal ^= temp1 ^ sum2
curByte = ord(src[i])
if not decryption:
keyXorVal = curByte * 257;
curByte = ((curByte ^ (byteXorVal >> 8)) ^ byteXorVal) & 0xFF
if decryption:
keyXorVal = curByte * 257;
for j in xrange(8):
wkey[j] ^= keyXorVal;
dst+=chr(curByte)
return dst
def checksumPid(s):
letters = "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789"
crc = (~binascii.crc32(s,-1))&0xFFFFFFFF
crc = crc ^ (crc >> 16)
res = s
l = len(letters)
for i in (0,1):
b = crc & 0xff
pos = (b // l) ^ (b % l)
res += letters[pos%l]
crc >>= 8
return res
def getSizeOfTrailingDataEntries(ptr, size, flags):
def getSizeOfTrailingDataEntry(ptr, size):
bitpos, result = 0, 0
if size <= 0:
return result
while True:
v = ord(ptr[size-1])
result |= (v & 0x7F) << bitpos
bitpos += 7
size -= 1
if (v & 0x80) != 0 or (bitpos >= 28) or (size == 0):
return result
num = 0
flags >>= 1
while flags:
if flags & 1:
num += getSizeOfTrailingDataEntry(ptr, size - num)
flags >>= 1
return num
class DrmStripper:
def loadSection(self, section):
if (section + 1 == self.num_sections):
endoff = len(self.data_file)
else:
endoff = self.sections[section + 1][0]
off = self.sections[section][0]
return self.data_file[off:endoff]
def patch(self, off, new):
self.data_file = self.data_file[:off] + new + self.data_file[off+len(new):]
def patchSection(self, section, new, in_off = 0):
if (section + 1 == self.num_sections):
endoff = len(self.data_file)
else:
endoff = self.sections[section + 1][0]
off = self.sections[section][0]
assert off + in_off + len(new) <= endoff
self.patch(off + in_off, new)
def parseDRM(self, data, count, pid):
pid = pid.ljust(16,'\0')
keyvec1 = "\x72\x38\x33\xB0\xB4\xF2\xE3\xCA\xDF\x09\x01\xD6\xE2\xE0\x3F\x96"
temp_key = PC1(keyvec1, pid, False)
temp_key_sum = sum(map(ord,temp_key)) & 0xff
found_key = None
for i in xrange(count):
verification, size, type, cksum, cookie = struct.unpack('>LLLBxxx32s', data[i*0x30:i*0x30+0x30])
cookie = PC1(temp_key, cookie)
ver,flags,finalkey,expiry,expiry2 = struct.unpack('>LL16sLL', cookie)
if verification == ver and cksum == temp_key_sum and (flags & 0x1F) == 1:
found_key = finalkey
break
return found_key
def __init__(self, data_file, pid):
if checksumPid(pid[0:-2]) != pid:
raise DrmException("invalid PID checksum")
pid = pid[0:-2]
self.data_file = data_file
header = data_file[0:72]
if header[0x3C:0x3C+8] != 'BOOKMOBI':
raise DrmException("invalid file format")
self.num_sections, = struct.unpack('>H', data_file[76:78])
self.sections = []
for i in xrange(self.num_sections):
offset, a1,a2,a3,a4 = struct.unpack('>LBBBB', data_file[78+i*8:78+i*8+8])
flags, val = a1, a2<<16|a3<<8|a4
self.sections.append( (offset, flags, val) )
sect = self.loadSection(0)
records, = struct.unpack('>H', sect[0x8:0x8+2])
mobi_length, = struct.unpack('>L',sect[0x14:0x18])
extra_data_flags = 0
if mobi_length >= 0xE4:
extra_data_flags, = struct.unpack('>L', sect[0xF0:0xF4])
crypto_type, = struct.unpack('>H', sect[0xC:0xC+2])
if crypto_type != 2:
raise DrmException("invalid encryption type: %d" % crypto_type)
# calculate the keys
drm_ptr, drm_count, drm_size, drm_flags = struct.unpack('>LLLL', sect[0xA8:0xA8+16])
found_key = self.parseDRM(sect[drm_ptr:drm_ptr+drm_size], drm_count, pid)
if not found_key:
raise DrmException("no key found. maybe the PID is incorrect")
# kill the drm keys
self.patchSection(0, "\0" * drm_size, drm_ptr)
# kill the drm pointers
self.patchSection(0, "\xff" * 4 + "\0" * 12, 0xA8)
# clear the crypto type
self.patchSection(0, "\0" * 2, 0xC)
# decrypt sections
print "Decrypting. Please wait...",
for i in xrange(1, records+1):
data = self.loadSection(i)
extra_size = getSizeOfTrailingDataEntries(data, len(data), extra_data_flags)
self.patchSection(i, PC1(found_key, data[0:len(data) - extra_size]))
print "done"
def getResult(self):
return self.data_file
print "MobiDeDrm v0.04. Copyright (c) 2008 The Dark Reverser"
if len(sys.argv)<4:
print "Removes protection from Mobipocket books"
print "Usage:"
print " mobidedrm infile.mobi outfile.mobi PID"
else:
infile = sys.argv[1]
outfile = sys.argv[2]
pid = sys.argv[3]
data_file = file(infile, 'rb').read()
try:
file(outfile, 'wb').write(DrmStripper(data_file, pid).getResult())
except DrmException, e:
print "Error: %s" % e

View File

@@ -0,0 +1,59 @@
on unlockfile(encryptedFile, MobiDeDRMPath, encryptionKey)
set encryptedFilePath to POSIX path of file encryptedFile
tell application "Finder" to <20>
set parent_folder to (container of file encryptedFile) as text
tell application "Finder" to set fileName to (name of file encryptedFile) as text
set unlockedFilePath to POSIX path of file (parent_folder & "Unlocked_" & fileName)
set shellcommand to "python \"" & MobiDeDRMPath & "\" \"" & encryptedFilePath & "\" \"" & unlockedFilePath & "\" '" & encryptionKey & "'"
try
--with timeout of 5 seconds
-- display dialog "About to Unlock " & fileName buttons {"Unlock"} default button 1 giving up after 1
--end timeout
end try
set result to do shell script shellcommand
try
if (offset of "Error" in result) > 0 then
with timeout of 5 seconds
display dialog "Can't unlock file " & fileName & ".
" & result buttons ("OK") default button 1 giving up after 5
end timeout
end if
end try
end unlockfile
on unlockfolder(encryptedFolder, MobiDeDRMPath, encryptionKey)
tell application "Finder" to set encryptedFileList to (every file in folder encryptedFolder) whose (name extension is "prc") or (name extension is "mobi")
tell application "Finder" to set encryptedFolderList to (every folder in folder encryptedFolder)
repeat with this_item in encryptedFileList
unlockfile(this_item as text, MobiDeDRMPath, encryptionKey)
end repeat
repeat with this_item in encryptedFolderList
unlockfolder(this_item as text, MobiDeDRMPath, encryptionKey)
end repeat
end unlockfolder
on run
set MobiDeDRMPath to POSIX path of file ((path to me as text) & "Contents:Resources:MobiDeDRM.py")
set encryptedFolder to choose folder with prompt "Please choose the folder of encrypted Mobipocket files."
set encryptionKey to (display dialog "Enter Mobipocket key for encrypted Mobipocket files." default answer "X12QIL1M3D" buttons {"Cancel", "OK"} default button 2)
set encryptionKey to text returned of encryptionKey
unlockfolder(encryptedFolder, MobiDeDRMPath, encryptionKey)
end run
on open some_items
set MobiDeDRMPath to POSIX path of file ((path to me as text) & "Contents:Resources:MobiDeDRM.py")
set encryptionKey to (display dialog "Enter Mobipocket key for encrypted Mobipocket files." default answer "X12QIL1M3D" buttons {"Cancel", "OK"} default button 2)
set encryptionKey to text returned of encryptionKey
repeat with this_item in some_items
if (folder of (info for this_item) is true) then
unlockfolder(this_item as text, MobiDeDRMPath, encryptionKey)
else
tell application "Finder" to set item_extension to name extension of file this_item
if item_extension is "prc" or item_extension is "mobi" then
unlockfile(this_item as text, MobiDeDRMPath, encryptionKey)
end if
end if
end repeat
end open

View File

@@ -0,0 +1,4 @@
{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf330
{\fonttbl}
{\colortbl;\red255\green255\blue255;}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 B