Guest User

DarkReverser

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

×