G2A Many GEOs
SHARE
TWEET

Untitled

a guest Jan 29th, 2009 3,616 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.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
RAW Paste Data
Ledger Nano X - The secure hardware wallet
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top