Teraz jest 28 mar 2024 15:14:04




Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 1 ] 
Usuwanie drmu z mobipocketów 
Autor Wiadomość
Admin

Dołączył(a): 13 cze 2008 14:47:02
Posty: 2835
Lokalizacja: Gdańsk
eCzytnik: kindle
Post Usuwanie drmu z mobipocketów
Problem dotyczył mnie już jakiś czas temu, gdy przeszedłem z fabrycznego oprogramowania jinke na OpenInkpota. Ponieważ OpenInkpot nie otwiera ebooków z drmem, ebooki z ebook.pl przestały mi działać (wtedy jeszcze na ebook.pl znajdowały się tylko utwory z public domain, dzisiaj jak tam zajrzałem to widzę że się sporo zmieniło).
Teraz pewnie więcej osób będzie miało ten problem z powodu przechodzenia producentów czytników na drmy od Adobe i wymuszonego porzucenia wsparcia dla szyfrowanych mobipocketów.

Pomaga przepuszczenie ebooka przez taki skrypt:
Kod:
#!/usr/bin/python

# 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

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 getSizeOfTrailingDataEntries(ptr, size, flags):
   def getSizeOfTrailingDataEntry(ptr, size):
      bitpos, result = 0, 0
      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):
      temp_key = binascii.unhexlify("723833b0b4f2e3cadf0901d6e2e03f96")
      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:
            found_key = finalkey
            break
      return found_key      


   def __init__(self, data_file):

      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])
      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)
      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.02. Copyright (c) 2008 The Dark Reverser"
if len(sys.argv)<3:
   print "Removes protection from Mobipocket books"
   print "Usage:"
   print "  mobidecrypt infile.mobi outfile.mobi"
else: 
   infile = sys.argv[1]
   outfile = sys.argv[2]
   data_file = file(infile, 'rb').read()
   try:
      file(outfile, 'wb').write(DrmStripper(data_file).getResult())
   except DrmException, e:
      print "Error: %s" % e



Pod linuksem (jeśli mamy w systemie pythona - większość dystrybucji ma) wystarczy zapisać powyższy kod w pliku, nadać mu prawa do wykonywania, i odpalić w terminalu skrypt z parametrami nazwa_ebooka nazwa_ebooka_bez_drm.
Windowsa nie używam, więc nie wiem jak wy tam macie. W komentarzu piszą, że jest na windowsa jakiś ActiveState Python.

Nie wiem na jakie pliki to działa (poza tym że działało na ebooka z ebook.pl). Zamieszczam ten skrypt znaleziony w sieci w celach edukacyjnych.

_________________
Zgred - Rafał Ziemkiewicz napisał(a):
Dziś trzeba pisać o mieczach, czarach, toporach i wojowniczkach w blaszanych bikini, wszystko inne to już jest nisza w niszy. Albo o nastoletnich wampirach.
Porównywarka cen ebooków


09 paź 2009 11:46:34
Zobacz profil WWW
Wyświetl posty nie starsze niż:  Sortuj wg  
Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 1 ] 


Kto przegląda forum

Użytkownicy przeglądający to forum: Brak zalogowanych użytkowników i 1 gość


Nie możesz rozpoczynać nowych wątków
Nie możesz odpowiadać w wątkach
Nie możesz edytować swoich postów
Nie możesz usuwać swoich postów

Skocz do: