Guest User

brutusbum

a guest
Sep 10th, 2009
258
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # This is a python script. You need a Python interpreter to run it.
  2. # For example, ActiveState Python, which exists for windows.
  3. #
  4. # Changelog
  5. #  0.01 - Initial version
  6. #  0.02 - Huffdic compressed books were not properly decrypted
  7. #  0.04 - Wasn't sanity checking size of data record
  8. #  0.05 - It seems that the extra data flags take two bytes not four
  9. #  0.06 - And that low bit does mean something after all :-)
  10.  
  11. import sys,struct,binascii
  12.  
  13. class DrmException(Exception):
  14.     pass
  15.  
  16. #implementation of Pukall Cipher 1
  17. def PC1(key, src, decryption=True):
  18.     sum1 = 0;
  19.     sum2 = 0;
  20.     keyXorVal = 0;
  21.     if len(key)!=16:
  22.         print "Bad key length!"
  23.         return None
  24.     wkey = []
  25.     for i in xrange(8):
  26.         wkey.append(ord(key[i*2])<<8 | ord(key[i*2+1]))
  27.  
  28.     dst = ""
  29.     for i in xrange(len(src)):
  30.         temp1 = 0;
  31.         byteXorVal = 0;
  32.         for j in xrange(8):
  33.             temp1 ^= wkey[j]
  34.             sum2  = (sum2+j)*20021 + sum1
  35.             sum1  = (temp1*346)&0xFFFF
  36.             sum2  = (sum2+sum1)&0xFFFF
  37.             temp1 = (temp1*20021+1)&0xFFFF
  38.             byteXorVal ^= temp1 ^ sum2
  39.         curByte = ord(src[i])
  40.         if not decryption:
  41.             keyXorVal = curByte * 257;
  42.         curByte = ((curByte ^ (byteXorVal >> 8)) ^ byteXorVal) & 0xFF
  43.         if decryption:
  44.             keyXorVal = curByte * 257;
  45.         for j in xrange(8):
  46.             wkey[j] ^= keyXorVal;
  47.         dst+=chr(curByte)
  48.     return dst
  49.  
  50. def checksumPid(s):
  51.     letters = "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789"
  52.     crc = (~binascii.crc32(s,-1))&0xFFFFFFFF
  53.     crc = crc ^ (crc >> 16)
  54.     res = s
  55.     l = len(letters)
  56.     for i in (0,1):
  57.         b = crc & 0xff
  58.         pos = (b // l) ^ (b % l)
  59.         res += letters[pos%l]
  60.         crc >>= 8
  61.     return res
  62.  
  63. def getSizeOfTrailingDataEntries(ptr, size, flags):
  64.     def getSizeOfTrailingDataEntry(ptr, size):
  65.         bitpos, result = 0, 0
  66.         if size <= 0:
  67.             return result
  68.         while True:
  69.             v = ord(ptr[size-1])
  70.             result |= (v & 0x7F) << bitpos
  71.             bitpos += 7
  72.             size -= 1
  73.             if (v & 0x80) != 0 or (bitpos >= 28) or (size == 0):
  74.                 return result
  75.     num = 0
  76.     testflags = flags >> 1
  77.     while testflags:
  78.         if testflags & 1:
  79.             num += getSizeOfTrailingDataEntry(ptr, size - num)
  80.         testflags >>= 1
  81.     if flags & 1:
  82.         num += (ord(ptr[size - num - 1]) & 0x3) + 1
  83.     return num
  84. class DrmStripper:
  85.     def loadSection(self, section):
  86.         if (section + 1 == self.num_sections):
  87.             endoff = len(self.data_file)
  88.         else:
  89.             endoff = self.sections[section + 1][0]
  90.         off = self.sections[section][0]
  91.         return self.data_file[off:endoff]
  92.  
  93.     def patch(self, off, new)
  94.         self.data_file = self.data_file[:off] + new + self.data_file[off+len(new):]
  95.  
  96.     def patchSection(self, section, new, in_off = 0):
  97.         if (section + 1 == self.num_sections):
  98.             endoff = len(self.data_file)
  99.         else:
  100.             endoff = self.sections[section + 1][0]
  101.         off = self.sections[section][0]
  102.         assert off + in_off + len(new) <= endoff
  103.         self.patch(off + in_off, new)
  104.  
  105.     def parseDRM(self, data, count, pid):
  106.         pid = pid.ljust(16,'\0')
  107.         keyvec1 = "\x72\x38\x33\xB0\xB4\xF2\xE3\xCA\xDF\x09\x01\xD6\xE2\xE0\x3F\x96"
  108.         temp_key = PC1(keyvec1, pid, False)
  109.         temp_key_sum = sum(map(ord,temp_key)) & 0xff
  110.         found_key = None
  111.         for i in xrange(count):
  112.             verification, size, type, cksum, cookie = struct.unpack('>LLLBxxx32s', data[i*0x30:i*0x30+0x30])
  113.             cookie = PC1(temp_key, cookie)
  114.             ver,flags,finalkey,expiry,expiry2 = struct.unpack('>LL16sLL', cookie)
  115.             if verification == ver and cksum == temp_key_sum and (flags & 0x1F) == 1:
  116.                 found_key = finalkey
  117.                 break
  118.         return found_key       
  119.  
  120.  
  121.     def __init__(self, data_file, pid):
  122.  
  123.         if checksumPid(pid[0:-2]) != pid:
  124.             raise DrmException("invalid PID checksum")
  125.         pid = pid[0:-2]
  126.        
  127.         self.data_file = data_file
  128.         header = data_file[0:72]
  129.         if header[0x3C:0x3C+8] != 'BOOKMOBI':
  130.             raise DrmException("invalid file format")
  131.         self.num_sections, = struct.unpack('>H', data_file[76:78])
  132.  
  133.         self.sections = []
  134.         for i in xrange(self.num_sections):
  135.             offset, a1,a2,a3,a4 = struct.unpack('>LBBBB', data_file[78+i*8:78+i*8+8])
  136.             flags, val = a1, a2<<16|a3<<8|a4
  137.             self.sections.append( (offset, flags, val) )
  138.  
  139.         sect = self.loadSection(0)
  140.         records, = struct.unpack('>H', sect[0x8:0x8+2])
  141.         mobi_length, = struct.unpack('>L',sect[0x14:0x18])
  142.         extra_data_flags = 0
  143.         if mobi_length >= 0xE4:
  144.             extra_data_flags, = struct.unpack('>H', sect[0xF2:0xF4])
  145.         crypto_type, = struct.unpack('>H', sect[0xC:0xC+2])
  146.         if crypto_type != 2:
  147.             raise DrmException("invalid encryption type: %d" % crypto_type)
  148.  
  149.         # calculate the keys
  150.         drm_ptr, drm_count, drm_size, drm_flags = struct.unpack('>LLLL', sect[0xA8:0xA8+16])
  151.         found_key = self.parseDRM(sect[drm_ptr:drm_ptr+drm_size], drm_count, pid)
  152.         if not found_key:
  153.             raise DrmException("no key found. maybe the PID is incorrect")
  154.  
  155.         # kill the drm keys
  156.         self.patchSection(0, "\0" * drm_size, drm_ptr)
  157.         # kill the drm pointers
  158.         self.patchSection(0, "\xff" * 4 + "\0" * 12, 0xA8)
  159.         # clear the crypto type
  160.         self.patchSection(0, "\0" * 2, 0xC)
  161.  
  162.         # decrypt sections
  163.         print "Decrypting. Please wait...",
  164.         for i in xrange(1, records+1):
  165.             data = self.loadSection(i)
  166.             extra_size = getSizeOfTrailingDataEntries(data, len(data), extra_data_flags)
  167.             self.patchSection(i, PC1(found_key, data[0:len(data) - extra_size]))
  168.         print "done"
  169.     def getResult(self):
  170.         return self.data_file
  171.  
  172. print "MobiDeDrm v0.06. Copyright (c) 2008 The Dark Reverser"
  173. if len(sys.argv)<4:
  174.     print "Removes protection from Mobipocket books"
  175.     print "Usage:"
  176.     print "  mobidedrm infile.mobi outfile.mobi PID"
  177. else:  
  178.     infile = sys.argv[1]
  179.     outfile = sys.argv[2]
  180.     pid = sys.argv[3]
  181.     data_file = file(infile, 'rb').read()
  182.     try:
  183.         file(outfile, 'wb').write(DrmStripper(data_file, pid).getResult())
  184.     except DrmException, e:
  185.         print "Error: %s" % e
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

Ă—