parent
b1feca321d
commit
a30aace99c
Binary file not shown.
@ -0,0 +1,238 @@
|
||||
Only in kindle4.0.2.1: build
|
||||
diff -r -u10 kindle4.0.2.1_orig/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali kindle4.0.2.1/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali
|
||||
--- kindle4.0.2.1_orig/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali 2013-05-22 18:39:03.000000000 -0500
|
||||
+++ kindle4.0.2.1/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali 2013-05-23 16:54:53.000000000 -0500
|
||||
@@ -36,20 +36,22 @@
|
||||
.field private maxCpuSpeed:J
|
||||
|
||||
.field private maxMemory:J
|
||||
|
||||
.field private minCpuSpeed:J
|
||||
|
||||
.field private resources:Landroid/content/res/Resources;
|
||||
|
||||
.field private security:Lcom/mobipocket/android/library/reader/AndroidSecurity;
|
||||
|
||||
+.field private pidList:Ljava/lang/String;
|
||||
+
|
||||
.field private totalMemory:J
|
||||
|
||||
|
||||
# direct methods
|
||||
.method static constructor <clinit>()V
|
||||
.locals 1
|
||||
|
||||
.prologue
|
||||
.line 30
|
||||
const-class v0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;
|
||||
@@ -72,20 +74,24 @@
|
||||
.prologue
|
||||
.line 130
|
||||
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
|
||||
|
||||
.line 131
|
||||
iput-object p1, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->security:Lcom/mobipocket/android/library/reader/AndroidSecurity;
|
||||
|
||||
.line 132
|
||||
iput-object p2, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->deviceType:Lcom/amazon/kcp/application/AmazonDeviceType;
|
||||
|
||||
+ const-string v0, "Open DRMed book to show PID list."
|
||||
+
|
||||
+ iput-object v0, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String;
|
||||
+
|
||||
.line 133
|
||||
sget-object v0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->TAG:Ljava/lang/String;
|
||||
|
||||
new-instance v0, Ljava/lang/StringBuilder;
|
||||
|
||||
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
|
||||
|
||||
const-string v1, "Device Type is set to \""
|
||||
|
||||
invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
||||
@@ -1235,10 +1241,33 @@
|
||||
move-result-wide v0
|
||||
|
||||
iput-wide v0, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->totalMemory:J
|
||||
|
||||
.line 308
|
||||
:cond_0
|
||||
iget-wide v0, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->totalMemory:J
|
||||
|
||||
return-wide v0
|
||||
.end method
|
||||
+
|
||||
+.method public getPidList()Ljava/lang/String;
|
||||
+ .locals 1
|
||||
+
|
||||
+ .prologue
|
||||
+ .line 15
|
||||
+ iget-object v0, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String;
|
||||
+
|
||||
+ return-object v0
|
||||
+.end method
|
||||
+
|
||||
+.method public setPidList(Ljava/lang/String;)V
|
||||
+ .locals 0
|
||||
+ .parameter "value"
|
||||
+
|
||||
+ .prologue
|
||||
+ .line 11
|
||||
+ iput-object p1, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String;
|
||||
+
|
||||
+ .line 12
|
||||
+ return-void
|
||||
+.end method
|
||||
+
|
||||
diff -r -u10 kindle4.0.2.1_orig/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali kindle4.0.2.1/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali
|
||||
--- kindle4.0.2.1_orig/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali 2013-05-22 18:39:03.000000000 -0500
|
||||
+++ kindle4.0.2.1/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali 2013-05-23 16:55:58.000000000 -0500
|
||||
@@ -23,10 +23,16 @@
|
||||
.end method
|
||||
|
||||
.method public abstract getDeviceTypeId()Ljava/lang/String;
|
||||
.end method
|
||||
|
||||
.method public abstract getOsVersion()Ljava/lang/String;
|
||||
.end method
|
||||
|
||||
.method public abstract getPid()Ljava/lang/String;
|
||||
.end method
|
||||
+
|
||||
+.method public abstract getPidList()Ljava/lang/String;
|
||||
+.end method
|
||||
+
|
||||
+.method public abstract setPidList(Ljava/lang/String;)V
|
||||
+.end method
|
||||
diff -r -u10 kindle4.0.2.1_orig/smali/com/amazon/kcp/info/AboutActivity.smali kindle4.0.2.1/smali/com/amazon/kcp/info/AboutActivity.smali
|
||||
--- kindle4.0.2.1_orig/smali/com/amazon/kcp/info/AboutActivity.smali 2013-05-22 18:39:03.000000000 -0500
|
||||
+++ kindle4.0.2.1/smali/com/amazon/kcp/info/AboutActivity.smali 2013-05-23 17:18:14.000000000 -0500
|
||||
@@ -486,20 +486,71 @@
|
||||
.end local v2 #screenDpi:Ljava/lang/String;
|
||||
:cond_0
|
||||
iget-object v5, p0, Lcom/amazon/kcp/info/AboutActivity;->detailItemList:Ljava/util/List;
|
||||
|
||||
invoke-interface {v5, v0}, Ljava/util/List;->add(Ljava/lang/Object;)Z
|
||||
|
||||
.line 317
|
||||
return-void
|
||||
.end method
|
||||
|
||||
+.method private populatePIDList()V
|
||||
+ .locals 7
|
||||
+
|
||||
+ .prologue
|
||||
+ .line 313
|
||||
+ invoke-static {}, Lcom/amazon/kcp/application/DeviceInformationProviderFactory;->getProvider()Lcom/amazon/kcp/application/IDeviceInformationProvider;
|
||||
+
|
||||
+ move-result-object v0
|
||||
+
|
||||
+ invoke-interface {v0}, Lcom/amazon/kcp/application/IDeviceInformationProvider;->getPidList()Ljava/lang/String;
|
||||
+
|
||||
+ move-result-object v1
|
||||
+
|
||||
+ .line 314
|
||||
+ .local v1, PidList:Ljava/lang/String;
|
||||
+ iget-object v3, p0, Lcom/amazon/kcp/info/AboutActivity;->groupItemList:Ljava/util/List;
|
||||
+
|
||||
+ new-instance v4, Lcom/amazon/kcp/info/AboutActivity$GroupItem;
|
||||
+
|
||||
+ const-string v5, "PID List"
|
||||
+
|
||||
+ const v6, 0x1
|
||||
+
|
||||
+ invoke-direct {v4, p0, v5, v6}, Lcom/amazon/kcp/info/AboutActivity$GroupItem;-><init>(Lcom/amazon/kcp/info/AboutActivity;Ljava/lang/String;Z)V
|
||||
+
|
||||
+ invoke-interface {v3, v4}, Ljava/util/List;->add(Ljava/lang/Object;)Z
|
||||
+
|
||||
+ .line 315
|
||||
+ new-instance v2, Ljava/util/ArrayList;
|
||||
+
|
||||
+ invoke-direct {v2}, Ljava/util/ArrayList;-><init>()V
|
||||
+
|
||||
+ .line 316
|
||||
+ .local v2, children:Ljava/util/List;,"Ljava/util/List<Lcom/amazon/kcp/info/AboutActivity$DetailItem;>;"
|
||||
+ new-instance v3, Lcom/amazon/kcp/info/AboutActivity$DetailItem;
|
||||
+
|
||||
+ const-string v4, "PIDs"
|
||||
+
|
||||
+ invoke-direct {v3, p0, v4, v1}, Lcom/amazon/kcp/info/AboutActivity$DetailItem;-><init>(Lcom/amazon/kcp/info/AboutActivity;Ljava/lang/String;Ljava/lang/String;)V
|
||||
+
|
||||
+ invoke-interface {v2, v3}, Ljava/util/List;->add(Ljava/lang/Object;)Z
|
||||
+
|
||||
+ .line 317
|
||||
+ iget-object v3, p0, Lcom/amazon/kcp/info/AboutActivity;->detailItemList:Ljava/util/List;
|
||||
+
|
||||
+ invoke-interface {v3, v2}, Ljava/util/List;->add(Ljava/lang/Object;)Z
|
||||
+
|
||||
+ .line 318
|
||||
+ return-void
|
||||
+.end method
|
||||
+
|
||||
.method private populateDisplayItems()V
|
||||
.locals 1
|
||||
|
||||
.prologue
|
||||
.line 171
|
||||
iget-object v0, p0, Lcom/amazon/kcp/info/AboutActivity;->groupItemList:Ljava/util/List;
|
||||
|
||||
if-nez v0, :cond_0
|
||||
|
||||
.line 173
|
||||
@@ -531,20 +582,22 @@
|
||||
|
||||
.line 192
|
||||
invoke-direct {p0}, Lcom/amazon/kcp/info/AboutActivity;->populateRamInformation()V
|
||||
|
||||
.line 193
|
||||
invoke-direct {p0}, Lcom/amazon/kcp/info/AboutActivity;->populateStorageInformation()V
|
||||
|
||||
.line 194
|
||||
invoke-direct {p0}, Lcom/amazon/kcp/info/AboutActivity;->populateDisplayInformation()V
|
||||
|
||||
+ invoke-direct {p0}, Lcom/amazon/kcp/info/AboutActivity;->populatePIDList()V
|
||||
+
|
||||
.line 195
|
||||
return-void
|
||||
|
||||
.line 177
|
||||
:cond_0
|
||||
iget-object v0, p0, Lcom/amazon/kcp/info/AboutActivity;->groupItemList:Ljava/util/List;
|
||||
|
||||
invoke-interface {v0}, Ljava/util/List;->clear()V
|
||||
|
||||
goto :goto_0
|
||||
diff -r -u10 kindle4.0.2.1_orig/smali/com/amazon/system/security/Security.smali kindle4.0.2.1/smali/com/amazon/system/security/Security.smali
|
||||
--- kindle4.0.2.1_orig/smali/com/amazon/system/security/Security.smali 2013-05-22 18:39:04.000000000 -0500
|
||||
+++ kindle4.0.2.1/smali/com/amazon/system/security/Security.smali 2013-05-23 17:19:05.000000000 -0500
|
||||
@@ -920,20 +920,30 @@
|
||||
|
||||
.line 350
|
||||
:cond_2
|
||||
add-int/lit8 v8, v8, 0x1
|
||||
|
||||
.line 351
|
||||
sget-object v0, Lcom/amazon/system/security/Security;->CUSTOM_PID_FOR_BUNDLED_DICTIONARY_DRM:Ljava/lang/String;
|
||||
|
||||
aput-object v0, v6, v8
|
||||
|
||||
+ invoke-static {}, Lcom/amazon/kcp/application/DeviceInformationProviderFactory;->getProvider()Lcom/amazon/kcp/application/IDeviceInformationProvider;
|
||||
+
|
||||
+ move-result-object v5
|
||||
+
|
||||
+ invoke-static {v6}, Ljava/util/Arrays;->toString([Ljava/lang/Object;)Ljava/lang/String;
|
||||
+
|
||||
+ move-result-object v2
|
||||
+
|
||||
+ invoke-interface {v5, v2}, Lcom/amazon/kcp/application/IDeviceInformationProvider;->setPidList(Ljava/lang/String;)V
|
||||
+
|
||||
.line 353
|
||||
return-object v6
|
||||
.end method
|
||||
|
||||
|
||||
# virtual methods
|
||||
.method public customDrmOnly()I
|
||||
.locals 1
|
||||
|
||||
.prologue
|
@ -0,0 +1,231 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Updated September 2013 by Anon
|
||||
# Version 2.01
|
||||
# Incorporated minor fixes posted at Apprentice Alf's.
|
||||
#
|
||||
# Updates July 2012 by Michael Newton
|
||||
# PWSD ID is no longer a MAC address, but should always
|
||||
# be stored in the registry. Script now works with OS X
|
||||
# and checks plist for values instead of registry. Must
|
||||
# have biplist installed for OS X support.
|
||||
#
|
||||
##########################################################
|
||||
# KOBO DRM CRACK BY #
|
||||
# PHYSISTICATED #
|
||||
##########################################################
|
||||
# This app was made for Python 2.7 on Windows 32-bit
|
||||
#
|
||||
# This app needs pycrypto - get from here:
|
||||
# http://www.voidspace.org.uk/python/modules.shtml
|
||||
#
|
||||
# Usage: obok.py
|
||||
# Choose the book you want to decrypt
|
||||
#
|
||||
# Shouts to my krew - you know who you are - and one in
|
||||
# particular who gave me a lot of help with this - thank
|
||||
# you so much!
|
||||
#
|
||||
# Kopimi /K\
|
||||
# Keep sharing, keep copying, but remember that nothing is
|
||||
# for free - make sure you compensate your favorite
|
||||
# authors - and cut out the middle man whenever possible
|
||||
# ;) ;) ;)
|
||||
#
|
||||
# DRM AUTOPSY
|
||||
# The Kobo DRM was incredibly easy to crack, but it took
|
||||
# me months to get around to making this. Here's the
|
||||
# basics of how it works:
|
||||
# 1: Get MAC address of first NIC in ipconfig (sometimes
|
||||
# stored in registry as pwsdid)
|
||||
# 2: Get user ID (stored in tons of places, this gets it
|
||||
# from HKEY_CURRENT_USER\Software\Kobo\Kobo Desktop
|
||||
# Edition\Browser\cookies)
|
||||
# 3: Concatenate and SHA256, take the second half - this
|
||||
# is your master key
|
||||
# 4: Open %LOCALAPPDATA%\Kobo Desktop Editions\Kobo.sqlite
|
||||
# and dump content_keys
|
||||
# 5: Unbase64 the keys, then decode these with the master
|
||||
# key - these are your page keys
|
||||
# 6: Unzip EPUB of your choice, decrypt each page with its
|
||||
# page key, then zip back up again
|
||||
#
|
||||
# WHY USE THIS WHEN INEPT WORKS FINE? (adobe DRM stripper)
|
||||
# Inept works very well, but authors on Kobo can choose
|
||||
# what DRM they want to use - and some have chosen not to
|
||||
# let people download them with Adobe Digital Editions -
|
||||
# they would rather lock you into a single platform.
|
||||
#
|
||||
# With Obok, you can sync Kobo Desktop, decrypt all your
|
||||
# ebooks, and then use them on whatever device you want
|
||||
# - you bought them, you own them, you can do what you
|
||||
# like with them.
|
||||
#
|
||||
# Obok is Kobo backwards, but it is also means "next to"
|
||||
# in Polish.
|
||||
# When you buy a real book, it is right next to you. You
|
||||
# can read it at home, at work, on a train, you can lend
|
||||
# it to a friend, you can scribble on it, and add your own
|
||||
# explanations/translations.
|
||||
#
|
||||
# Obok gives you this power over your ebooks - no longer
|
||||
# are you restricted to one device. This allows you to
|
||||
# embed foreign fonts into your books, as older Kobo's
|
||||
# can't display them properly. You can read your books
|
||||
# on your phones, in different PC readers, and different
|
||||
# ereader devices. You can share them with your friends
|
||||
# too, if you like - you can do that with a real book
|
||||
# after all.
|
||||
#
|
||||
"""
|
||||
Decrypt Kobo encrypted EPUB books.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
if sys.platform.startswith('win'):
|
||||
import _winreg
|
||||
elif sys.platform.startswith('darwin'):
|
||||
from biplist import readPlist
|
||||
import re
|
||||
import string
|
||||
import hashlib
|
||||
import sqlite3
|
||||
import base64
|
||||
import binascii
|
||||
import zipfile
|
||||
from Crypto.Cipher import AES
|
||||
|
||||
def SHA256(raw):
|
||||
return hashlib.sha256(raw).hexdigest()
|
||||
|
||||
def RemoveAESPadding(contents):
|
||||
lastchar = binascii.b2a_hex(contents[-1:])
|
||||
strlen = int(lastchar, 16)
|
||||
padding = strlen
|
||||
if(strlen == 1):
|
||||
return contents[:-1]
|
||||
if(strlen < 16):
|
||||
for i in range(strlen):
|
||||
testchar = binascii.b2a_hex(contents[-strlen:-(strlen-1)])
|
||||
if(testchar != lastchar):
|
||||
padding = 0
|
||||
if(padding > 0):
|
||||
contents = contents[:-padding]
|
||||
return contents
|
||||
|
||||
def GetVolumeKeys(dbase, enc):
|
||||
volumekeys = {}
|
||||
for row in dbase.execute("SELECT * from content_keys"):
|
||||
if(row[0] not in volumekeys):
|
||||
volumekeys[row[0]] = {}
|
||||
volumekeys[row[0]][row[1]] = {}
|
||||
volumekeys[row[0]][row[1]]["encryptedkey"] = base64.b64decode(row[2])
|
||||
volumekeys[row[0]][row[1]]["decryptedkey"] = enc.decrypt(volumekeys[row[0]][row[1]]["encryptedkey"])
|
||||
# get book name
|
||||
for key in volumekeys.keys():
|
||||
volumekeys[key]["title"] = dbase.execute("SELECT Title from content where ContentID = '%s'" % (key)).fetchone()[0]
|
||||
return volumekeys
|
||||
|
||||
def ByteArrayToString(bytearr):
|
||||
wincheck = re.match("@ByteArray\\((.+)\\)", bytearr)
|
||||
if wincheck:
|
||||
return wincheck.group(1)
|
||||
return bytearr
|
||||
|
||||
def GetUserHexKey(prefs = ""):
|
||||
"find wsuid and pwsdid"
|
||||
wsuid = ""
|
||||
pwsdid = ""
|
||||
if sys.platform.startswith('win'):
|
||||
regkey_browser = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, "Software\\Kobo\\Kobo Desktop Edition\\Browser")
|
||||
cookies = _winreg.QueryValueEx(regkey_browser, "cookies")
|
||||
bytearrays = cookies[0]
|
||||
elif sys.platform.startswith('darwin'):
|
||||
cookies = readPlist(prefs)
|
||||
bytearrays = cookies["Browser.cookies"]
|
||||
for bytearr in bytearrays:
|
||||
cookie = ByteArrayToString(bytearr)
|
||||
print cookie
|
||||
wsuidcheck = re.match("^wsuid=([0-9a-f-]+)", cookie)
|
||||
if(wsuidcheck):
|
||||
wsuid = wsuidcheck.group(1)
|
||||
pwsdidcheck = re.match("^pwsdid=([0-9a-f-]+)", cookie)
|
||||
if (pwsdidcheck):
|
||||
pwsdid = pwsdidcheck.group(1)
|
||||
|
||||
if(wsuid == "" or pwsdid == ""):
|
||||
print "wsuid or pwsdid key not found :/"
|
||||
exit()
|
||||
preuserkey = string.join((pwsdid, wsuid), "")
|
||||
print SHA256(pwsdid)
|
||||
userkey = SHA256(preuserkey)
|
||||
return userkey[32:]
|
||||
|
||||
# get dirs
|
||||
if sys.platform.startswith('win'):
|
||||
delim = "\\"
|
||||
if (sys.getwindowsversion().major > 5):
|
||||
kobodir = string.join((os.environ['LOCALAPPDATA'], "Kobo\\Kobo Desktop Edition"), delim)
|
||||
else:
|
||||
kobodir = string.join((os.environ['USERPROFILE'], "Local Settings\\Application Data\\Kobo\\Kobo Desktop Edition"), delim)
|
||||
prefs = ""
|
||||
elif sys.platform.startswith('darwin'):
|
||||
delim = "/"
|
||||
kobodir = string.join((os.environ['HOME'], "Library/Application Support/Kobo/Kobo Desktop Edition"), delim)
|
||||
prefs = string.join((os.environ['HOME'], "Library/Preferences/com.kobo.Kobo Desktop Edition.plist"), delim)
|
||||
sqlitefile = string.join((kobodir, "Kobo.sqlite"), delim)
|
||||
bookdir = string.join((kobodir, "kepub"), delim)
|
||||
|
||||
# get key
|
||||
userkeyhex = GetUserHexKey(prefs)
|
||||
# load into AES
|
||||
userkey = binascii.a2b_hex(userkeyhex)
|
||||
enc = AES.new(userkey, AES.MODE_ECB)
|
||||
|
||||
# open sqlite
|
||||
conn = sqlite3.connect(sqlitefile)
|
||||
dbcursor = conn.cursor()
|
||||
# get volume keys
|
||||
volumekeys = GetVolumeKeys(dbcursor, enc)
|
||||
|
||||
# choose a volumeID
|
||||
|
||||
volumeid = ""
|
||||
print "Choose a book to decrypt:"
|
||||
i = 1
|
||||
for key in volumekeys.keys():
|
||||
print "%d: %s" % (i, volumekeys[key]["title"])
|
||||
i += 1
|
||||
|
||||
num = input("...")
|
||||
|
||||
i = 1
|
||||
for key in volumekeys.keys():
|
||||
if(i == num):
|
||||
volumeid = key
|
||||
i += 1
|
||||
|
||||
if(volumeid == ""):
|
||||
exit()
|
||||
|
||||
zippath = string.join((bookdir, volumeid), delim)
|
||||
|
||||
z = zipfile.ZipFile(zippath, "r")
|
||||
# make filename out of Unicode alphanumeric and whitespace equivalents from title
|
||||
outname = "%s.epub" % (re.sub("[^\s\w]", "", volumekeys[volumeid]["title"], 0, re.UNICODE))
|
||||
zout = zipfile.ZipFile(outname, "w", zipfile.ZIP_DEFLATED)
|
||||
for filename in z.namelist():
|
||||
#print filename
|
||||
# read in and decrypt
|
||||
if(filename in volumekeys[volumeid]):
|
||||
# do decrypted version
|
||||
pagekey = volumekeys[volumeid][filename]["decryptedkey"]
|
||||
penc = AES.new(pagekey, AES.MODE_ECB)
|
||||
contents = RemoveAESPadding(penc.decrypt(z.read(filename)))
|
||||
# need to fix padding
|
||||
zout.writestr(filename, contents)
|
||||
else:
|
||||
zout.writestr(filename, z.read(filename))
|
||||
|
||||
print "Book saved as %s%s%s" % (os.getcwd(), delim, outname)
|
Loading…
Reference in New Issue