pastebin - collaborative debugging

pastebin is a collaborative debugging tool allowing you to share and modify code snippets while chatting on IRC, IM or a message board.

This site is developed to XHTML and CSS2 W3C standards. If you see this paragraph, your browser does not support those standards and you need to upgrade. Visit WaSP for a variety of options.

pastebin - collaborative debugging tool View Help


Posted by Anonymous on Thu 29 Jan 06:13
report abuse | download | new post

  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.03 - Wasn't checking MOBI header length
  8. #  0.04 - Wasn't sanity checking size of data record
  9. #  0.05 - It seems that the extra data flags take two bytes not four
  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.         flags >>= 1
  77.         while flags:
  78.                 if flags & 1:
  79.                         num += getSizeOfTrailingDataEntry(ptr, size - num)
  80.                 flags >>= 1            
  81.         return num
  82.  
  83.  
  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.  
  146.  
  147.                 crypto_type, = struct.unpack('>H', sect[0xC:0xC+2])
  148.                 if crypto_type != 2:
  149.                         raise DrmException("invalid encryption type: %d" % crypto_type)
  150.  
  151.                 # calculate the keys
  152.                 drm_ptr, drm_count, drm_size, drm_flags = struct.unpack('>LLLL', sect[0xA8:0xA8+16])
  153.                 found_key = self.parseDRM(sect[drm_ptr:drm_ptr+drm_size], drm_count, pid)
  154.                 if not found_key:
  155.                         raise DrmException("no key found. maybe the PID is incorrect")
  156.  
  157.                 # kill the drm keys
  158.                 self.patchSection(0, "\0" * drm_size, drm_ptr)
  159.                 # kill the drm pointers
  160.                 self.patchSection(0, "\xff" * 4 + "\0" * 12, 0xA8)
  161.                 # clear the crypto type
  162.                 self.patchSection(0, "\0" * 2, 0xC)
  163.  
  164.                 # decrypt sections
  165.                 print "Decrypting. Please wait...",
  166.                 for i in xrange(1, records+1):
  167.                         data = self.loadSection(i)
  168.                         extra_size = getSizeOfTrailingDataEntries(data, len(data), extra_data_flags)
  169.                         self.patchSection(i, PC1(found_key, data[0:len(data) - extra_size]))
  170.                 print "done"
  171.         def getResult(self):
  172.                 return self.data_file
  173.  
  174. print "MobiDeDrm v0.05. Copyright (c) 2008 The Dark Reverser"
  175. if len(sys.argv)<4:
  176.         print "Removes protection from Mobipocket books"
  177.         print "Usage:"
  178.         print "  mobidedrm infile.mobi outfile.mobi PID"
  179. else:  
  180.         infile = sys.argv[1]
  181.         outfile = sys.argv[2]
  182.         pid = sys.argv[3]
  183.         data_file = file(infile, 'rb').read()
  184.         try:
  185.                 file(outfile, 'wb').write(DrmStripper(data_file, pid).getResult())
  186.         except DrmException, e:
  187.                 print "Error: %s" % e

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with @@


Remember me so that I can delete my post