tools v5.4.1

This commit is contained in:
Apprentice Alf
2012-11-20 13:28:12 +00:00
parent 0dcd18d524
commit b661a6cdc5
80 changed files with 5564 additions and 4784 deletions

View File

@@ -0,0 +1,26 @@
// ==UserScript==
// @name BN-Dload
// @namespace http://www.mailinator.com/J-man
// @include https://mynook.barnesandnoble.com/library.html*
// @grant none
// @version 20121119
// ==/UserScript==
function doIt() {
if ($('#adl1').length == 0) {
$('[action$="deleteItem"]').each(function(index) {
if ($(this).parent().find('[action$="EDSDeliverItem.aspx"]').length == 0) {
var delid = $(this).find('input').attr('value');
$(this).after('<span class="vb2"></span><form id="adl' + index + '" action="https://edelivery.barnesandnoble.com/EDS/EDSDeliverItem.aspx" class="download"><input value="' + delid + '" type="hidden" name="delid"><input type="hidden" value="Browser" name="clienttype"><input type="hidden" value="browser" name="deviceinfo"><button class="download "name="download">Alternative Download</button></form>');
}
});
}
setTimeout (function() {
doIt();
}, 3000 );
}
doIt();

View File

@@ -0,0 +1,22 @@
To obtain unencrypted content from the B&N, you have to download it directly from the website. Unrooted Nook devices will not let you save your content to your PC.
If the downloaded file is encrypted, install and configure the ignoble plugin in Calibre to decrypt that.
Some content is not downloadable from the website, for instance magazines. The Greasemonkey script included in the tools modifies the myNook page of the Barnes and Noble website to show a download button for non-downloadable content. This will work until Barnes & Noble changes their website.
Prerequisites
1) Firefox: http://getfirefox.com
2) Greasemokey extension: https://addons.mozilla.org/nl/firefox/addon/greasemonkey/
One time installation
1) Install Firefox if not already done so;
2) Follow the above link to GreaseMonkey and click Add to Firefox
3) Restart Firefox
4) Go to (link to the script, best hosted somewhere, as .js usually opens in an editor)
5) A pop up should appear, stating you are about to install a GreaseMonkey user script.
6) Click on install
Use
1) Log in into your B&N account
2) Go to MyNook
3) An “Alternative download” should apppear next to normally non-downloadable content.

View File

@@ -5,8 +5,9 @@
#
# Changelog
# 1.00 - Initial version
# 1.01 - getPidList interface change
__version__ = '1.00'
__version__ = '1.01'
import sys
@@ -43,15 +44,15 @@ def getK4PCpids(path_to_ebook):
mb = mobidedrm.MobiBook(path_to_ebook,False)
else:
mb = topazextract.TopazBook(path_to_ebook)
md1, md2 = mb.getPIDMetaInfo()
return kgenpids.getPidList(md1, md2, True, [], [], [])
return kgenpids.getPidList(md1, md2)
def main(argv=sys.argv):
print ('getk4pcpids.py v%(__version__)s. '
'Copyright 2012 Apprentic Alf' % globals())
'Copyright 2012 Apprentice Alf' % globals())
if len(argv)<2 or len(argv)>3:
print "Gets the possible book-specific PIDs from K4PC for a particular book"
@@ -70,7 +71,7 @@ def main(argv=sys.argv):
if len(argv) is 3:
outfile = argv[2]
file(outfile, 'w').write(pidstring)
return 0
if __name__ == "__main__":

View File

@@ -33,6 +33,7 @@ import os, csv, getopt
import string
import re
import traceback
import time
buildXML = False
@@ -79,11 +80,16 @@ def cleanup_name(name):
def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
global buildXML
# handle the obvious cases at the beginning
if not os.path.isfile(infile):
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: Input file does not exist"
return 1
starttime = time.time()
print "Starting decryptBook routine."
mobi = True
magic3 = file(infile,'rb').read(3)
if magic3 == 'TPZ':
@@ -100,7 +106,7 @@ def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
print "Processing Book: ", title
filenametitle = cleanup_name(title)
outfilename = cleanup_name(bookname)
# generate 'sensible' filename, that will sort with the original name,
# but is close to the name from the file.
outlength = len(outfilename)
@@ -120,21 +126,29 @@ def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
# build pid list
md1, md2 = mb.getPIDMetaInfo()
pidlst = kgenpids.getPidList(md1, md2, k4, pids, serials, kInfoFiles)
pids.extend(kgenpids.getPidList(md1, md2, k4, serials, kInfoFiles))
print "Found {1:d} keys to try after {0:.1f} seconds".format(time.time()-starttime, len(pids))
try:
mb.processBook(pidlst)
mb.processBook(pids)
except mobidedrm.DrmException, e:
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: " + str(e) + "\nDRM Removal Failed.\n"
print "Failed to decrypted book after {0:.1f} seconds".format(time.time()-starttime)
return 1
except topazextract.TpzDRMError, e:
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: " + str(e) + "\nDRM Removal Failed.\n"
print "Failed to decrypted book after {0:.1f} seconds".format(time.time()-starttime)
return 1
except Exception, e:
print >>sys.stderr, ('K4MobiDeDrm v%(__version__)s\n' % globals()) + "Error: " + str(e) + "\nDRM Removal Failed.\n"
print "Failed to decrypted book after {0:.1f} seconds".format(time.time()-starttime)
return 1
print "Successfully decrypted book after {0:.1f} seconds".format(time.time()-starttime)
if mobi:
if mb.getPrintReplica():
outfile = os.path.join(outdir, outfilename + '_nodrm' + '.azw4')
@@ -143,6 +157,7 @@ def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
else:
outfile = os.path.join(outdir, outfilename + '_nodrm' + '.mobi')
mb.getMobiFile(outfile)
print "Saved decrypted book {1:s} after {0:.1f} seconds".format(time.time()-starttime, outfilename + '_nodrm')
return 0
# topaz:
@@ -161,7 +176,7 @@ def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
# remove internal temporary directory of Topaz pieces
mb.cleanup()
print "Saved decrypted Topaz book parts after {0:.1f} seconds".format(time.time()-starttime)
return 0

View File

@@ -31,7 +31,7 @@ def _load_crypto_libcrypto():
# AES_DECRYPT 0
# AES_MAXNR 14 (in bytes)
# AES_BLOCK_SIZE 16 (in bytes)
#
#
# struct aes_key_st {
# unsigned long rd_key[4 *(AES_MAXNR + 1)];
# int rounds;
@@ -494,56 +494,37 @@ class CryptUnprotectDataV3(object):
# Locate the .kindle-info files
def getKindleInfoFiles(kInfoFiles):
def getKindleInfoFiles():
# file searches can take a long time on some systems, so just look in known specific places.
kInfoFiles=[]
found = False
home = os.getenv('HOME')
# search for any .kinf2011 files in new location (Sep 2012)
cmdline = 'find "' + home + '/Library/Containers/com.amazon.Kindle/Data/Library/Application Support" -name ".kinf2011"'
cmdline = cmdline.encode(sys.getfilesystemencoding())
p1 = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False)
out1, out2 = p1.communicate()
reslst = out1.split('\n')
for resline in reslst:
if os.path.isfile(resline):
kInfoFiles.append(resline)
print('Found k4Mac kinf2011 file: ' + resline)
found = True
# search for any .kinf2011 files
cmdline = 'find "' + home + '/Library/Application Support" -name ".kinf2011"'
cmdline = cmdline.encode(sys.getfilesystemencoding())
p1 = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False)
out1, out2 = p1.communicate()
reslst = out1.split('\n')
for resline in reslst:
if os.path.isfile(resline):
kInfoFiles.append(resline)
print('Found k4Mac kinf2011 file: ' + resline)
found = True
# search for any .kindle-info files
cmdline = 'find "' + home + '/Library/Application Support" -name ".kindle-info"'
cmdline = cmdline.encode(sys.getfilesystemencoding())
p1 = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False)
out1, out2 = p1.communicate()
reslst = out1.split('\n')
kinfopath = 'NONE'
for resline in reslst:
if os.path.isfile(resline):
kInfoFiles.append(resline)
print('Found K4Mac kindle-info file: ' + resline)
found = True
# search for any .rainier*-kinf files
cmdline = 'find "' + home + '/Library/Application Support" -name ".rainier*-kinf"'
cmdline = cmdline.encode(sys.getfilesystemencoding())
p1 = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False)
out1, out2 = p1.communicate()
reslst = out1.split('\n')
for resline in reslst:
if os.path.isfile(resline):
kInfoFiles.append(resline)
print('Found k4Mac kinf file: ' + resline)
found = True
# check for .kinf2011 file in new location (App Store Kindle for Mac)
testpath = home + '/Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/storage/.kinf2011'
if os.path.isfile(testpath):
kInfoFiles.append(testpath)
print('Found k4Mac kinf2011 file: ' + testpath)
found = True
# check for .kinf2011 files
testpath = home + '/Library/Application Support/Kindle/storage/.kinf2011'
if os.path.isfile(testpath):
kInfoFiles.append(testpath)
print('Found k4Mac kinf2011 file: ' + testpath)
found = True
# check for .rainier-2.1.1-kinf files
testpath = home + '/Library/Application Support/Kindle/storage/.rainier-2.1.1-kinf'
if os.path.isfile(testpath):
kInfoFiles.append(testpath)
print('Found k4Mac rainier file: ' + testpath)
found = True
# check for .rainier-2.1.1-kinf files
testpath = home + '/Library/Application Support/Kindle/storage/.kindle-info'
if os.path.isfile(testpath):
kInfoFiles.append(testpath)
print('Found k4Mac kindle-info file: ' + testpath)
found = True
if not found:
print('No k4Mac kindle-info/kinf/kinf2011 files have been found.')
print('No k4Mac kindle-info/rainier/kinf2011 files have been found.')
return kInfoFiles
# determine type of kindle info provided and return a

View File

@@ -203,7 +203,8 @@ CryptUnprotectData = CryptUnprotectData()
# Locate all of the kindle-info style files and return as list
def getKindleInfoFiles(kInfoFiles):
def getKindleInfoFiles():
kInfoFiles = []
# some 64 bit machines do not have the proper registry key for some reason
# or the pythonn interface to the 32 vs 64 bit registry is broken
path = ""
@@ -226,34 +227,34 @@ def getKindleInfoFiles(kInfoFiles):
except RegError:
pass
found = False
found = False
if path == "":
print ('Could not find the folder in which to look for kinfoFiles.')
else:
print('searching for kinfoFiles in ' + path)
# first look for older kindle-info files
kinfopath = path +'\\Amazon\\Kindle For PC\\{AMAwzsaPaaZAzmZzZQzgZCAkZ3AjA_AY}\\kindle.info'
if os.path.isfile(kinfopath):
found = True
print('Found K4PC kindle.info file: ' + kinfopath)
kInfoFiles.append(kinfopath)
# now look for newer (K4PC 1.5.0 and later rainier.2.1.1.kinf file
kinfopath = path +'\\Amazon\\Kindle For PC\\storage\\rainier.2.1.1.kinf'
if os.path.isfile(kinfopath):
found = True
print('Found K4PC 1.5.X kinf file: ' + kinfopath)
kInfoFiles.append(kinfopath)
# now look for even newer (K4PC 1.6.0 and later) rainier.2.1.1.kinf file
kinfopath = path +'\\Amazon\\Kindle\\storage\\rainier.2.1.1.kinf'
if os.path.isfile(kinfopath):
found = True
print('Found K4PC 1.6.X kinf file: ' + kinfopath)
kInfoFiles.append(kinfopath)
# now look for even newer (K4PC 1.9.0 and later) .kinf2011 file
kinfopath = path +'\\Amazon\\Kindle\\storage\\.kinf2011'
if os.path.isfile(kinfopath):

View File

@@ -255,12 +255,12 @@ def getK4Pids(pidlst, rec209, token, kInfoFile):
return pidlst
def getPidList(md1, md2, k4, pids, serials, kInfoFiles):
def getPidList(md1, md2, k4 = True, serials=[], kInfoFiles=[]):
pidlst = []
if kInfoFiles is None:
kInfoFiles = []
if k4:
kInfoFiles = getKindleInfoFiles(kInfoFiles)
kInfoFiles.extend(getKindleInfoFiles())
for infoFile in kInfoFiles:
try:
pidlst = getK4Pids(pidlst, md1, md2, infoFile)
@@ -271,6 +271,4 @@ def getPidList(md1, md2, k4, pids, serials, kInfoFiles):
pidlst = getKindlePid(pidlst, md1, md2, serialnum)
except Exception, message:
print("Error getting PIDs from " + serialnum + ": " + message)
for pid in pids:
pidlst.append(pid)
return pidlst

View File

@@ -333,7 +333,7 @@ class MobiBook:
def getMobiVersion(self):
return self.mobi_version
def getPrintReplica(self):
return self.print_replica
@@ -381,7 +381,7 @@ class MobiBook:
raise DrmException("Not yet initialised with PID. Must be opened with Mobipocket Reader first.")
found_key, pid = self.parseDRM(self.sect[drm_ptr:drm_ptr+drm_size], drm_count, goodpids)
if not found_key:
raise DrmException("No key found in " + str(len(goodpids)) + " keys tried. Please report this failure for help.")
raise DrmException("No key found in " + str(len(goodpids)) + " keys tried. Read the FAQs at Alf's blog. Only if none apply, report this failure for help.")
# kill the drm keys
self.patchSection(0, "\0" * drm_size, drm_ptr)
# kill the drm pointers

View File

@@ -272,7 +272,7 @@ class TopazBook:
from calibre_plugins.k4mobidedrm import genbook
else:
import genbook
rv = genbook.generateBook(self.outdir, raw, fixedimage)
if rv == 0:
print "\nBook Successfully generated"
@@ -296,7 +296,7 @@ class TopazBook:
break
if not bookKey:
raise TpzDRMError("Topaz Book. No key found in " + str(len(pidlst)) + " keys tried. Please report this failure for help.")
raise TpzDRMError("Topaz Book. No key found in " + str(len(pidlst)) + " keys tried. Read the FAQs at Alf's blog. Only if none apply, report this failure for help.")
self.setBookKey(bookKey)
self.createBookDirectory()
@@ -306,7 +306,7 @@ class TopazBook:
from calibre_plugins.k4mobidedrm import genbook
else:
import genbook
rv = genbook.generateBook(self.outdir, raw, fixedimage)
if rv == 0:
print "\nBook Successfully generated"
@@ -374,7 +374,7 @@ class TopazBook:
zipUpDir(svgzip, self.outdir, 'svg')
zipUpDir(svgzip, self.outdir, 'img')
svgzip.close()
def getXMLZip(self, zipname):
xmlzip = zipfile.ZipFile(zipname,'w',zipfile.ZIP_DEFLATED, False)
targetdir = os.path.join(self.outdir,'xml')
@@ -442,11 +442,11 @@ def main(argv=sys.argv):
title = tb.getBookTitle()
print "Processing Book: ", title
keysRecord, keysRecordRecord = tb.getPIDMetaInfo()
pidlst = kgenpids.getPidList(keysRecord, keysRecordRecord, k4, pids, serials, kInfoFiles)
pids.extend(kgenpids.getPidList(keysRecord, keysRecordRecord, k4, serials, kInfoFiles))
try:
print "Decrypting Book"
tb.processBook(pidlst)
tb.processBook(pids)
print " Creating HTML ZIP Archive"
zipname = os.path.join(outdir, bookname + '_nodrm' + '.htmlz')

View File

@@ -0,0 +1,50 @@
Kindle for Android
------------------
Kindle for Android uses a different scheme to generate its books specific PIDs than Kindle for PC, Kindle for iPhone/iPad, and standalone Kindles.
Unfortunately, K4Android uses an "account secrets" file that would only be available if the device were jail-broken and even then someone would have to figure out how to decode this secret information in order to reverse the process.
Instead of trying to calculate the correct PIDs for each book from this primary data, "Me" (a commenter who posted to the ApprenticeAlf site) came up with a wonderful idea to simply modify the Kindle 3 for Android application to store the PIDs it uses to decode each book in its "about activity" window. This list of PIDS can then be provided to MobiDeDRM.py, which in its latest incarnations allows a comma separated list of pids to be passed in, to successfully remove the DRM from that book. Effectively "Me" has created an "Unswindle" for the Kindle for Android 3 application!
Obviously, to use "Me"'s approach, requires an Android Developer's Certificate (to sign the modified application) and access to and knowledge of the developer tools, but does not require anything to be jail-broken.
This is a copy the detailed instructions supplied by "Me" to the ApprenticeAlf blog in the comments. The kindle3.patch described below is included in this folder in the tools:
From the ApprenticeAlf Comments:
"Me" writes:
A better solution seems to create a patched version of the Kindle apk which either logs or displays its PID. I created a patch to both log the pid list and show it in the Kindle application in the about activity screen. The pid list isnt available until the DRMed book has been opened (and the list seem to differ for different books).
To create the patched kindle apk a certificate must be created (http://developer.android.com/guide/publishing/app-signing.html#cert) and the apktool must be build from source (all subprojects) as long as version 1.4.2 isnt released (http://code.google.com/p/android-apktool/wiki/BuildApktool).
These are the steps to pull the original apk from the Android device, uninstall it, create a patched apk and install that (tested on a rooted device, but I think all steps should also work on non-rooted devices):
adb pull /data/app/com.amazon.kindle-1.apk kindle3.apk
adb uninstall com.amazon.kindle
apktool d kindle3.apk kindle3
cd kindle3
patch -p1 < ../kindle3.patch
cd ..
apktool b kindle3 kindle3_patched.apk
jarsigner -verbose -keystore kindle.keystore kindle3_patched.apk kindle
zipalign -v 4 kindle3_patched.apk kindle3_signed.apk
adb install kindle3_signed.apk
kindle3.patch (based on kindle version 3.0.1.70) is available on pastebin:
http://pastebin.com/LNpgkcpP
Have fun!
Comment by me — June 9, 2011 @ 9:01 pm | Reply
Hi me,
Wow! Great work!!!!
With your patch, you have created the equivalent of Unswindle for the Kindle for Android app and it does not even require jailbreaking!
Very nice work indeed!
Comment by some_updates — June 10, 2011 @ 4:28 am | Reply

View File

@@ -0,0 +1,100 @@
diff -ru kindle3_orig/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali kindle3/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali
--- kindle3_orig/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali
+++ kindle3/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali
@@ -11,6 +11,8 @@
.field private security:Lcom/mobipocket/android/library/reader/AndroidSecurity;
+.field private pidList:Ljava/lang/String;
+
# direct methods
.method public constructor <init>(Lcom/mobipocket/android/library/reader/AndroidSecurity;Lcom/amazon/kcp/application/AndroidDeviceType;)V
@@ -28,6 +30,10 @@
.line 26
iput-object p2, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->deviceType:Lcom/amazon/kcp/application/AndroidDeviceType;
+ const-string v0, "Open DRMed book to show PID list."
+
+ iput-object v0, p0, Lcom/amazon/kcp/application/AndroidDeviceInformationProvider;->pidList:Ljava/lang/String;
+
.line 27
new-instance v0, Ljava/lang/StringBuilder;
@@ -175,4 +181,26 @@
move-result-object v0
return-object 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 -ru kindle3_orig/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali kindle3/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali
--- kindle3_orig/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali
+++ kindle3/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali
@@ -27,3 +27,9 @@
.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
\ No newline at end of file
diff -ru kindle3_orig/smali/com/amazon/kcp/info/AboutActivity.smali kindle3/smali/com/amazon/kcp/info/AboutActivity.smali
--- kindle3_orig/smali/com/amazon/kcp/info/AboutActivity.smali
+++ kindle3/smali/com/amazon/kcp/info/AboutActivity.smali
@@ -32,9 +32,11 @@
invoke-direct {v6, v1}, Ljava/util/ArrayList;-><init>(I)V
.line 36
- const v1, 0x7f0b0005
+ invoke-static {}, Lcom/amazon/kcp/application/DeviceInformationProviderFactory;->getProvider()Lcom/amazon/kcp/application/IDeviceInformationProvider;
- invoke-virtual {p0, v1}, Lcom/amazon/kcp/info/AboutActivity;->getString(I)Ljava/lang/String;
+ move-result-object v0
+
+ invoke-interface {v0}, Lcom/amazon/kcp/application/IDeviceInformationProvider;->getPidList()Ljava/lang/String;
move-result-object v1
diff -ru kindle3_orig/smali/com/amazon/system/security/Security.smali kindle3/smali/com/amazon/system/security/Security.smali
--- kindle3_orig/smali/com/amazon/system/security/Security.smali
+++ kindle3/smali/com/amazon/system/security/Security.smali
@@ -884,6 +884,15 @@
.line 332
:cond_1
+
+ const-string v1, "PID list"
+ invoke-static {}, Lcom/amazon/kcp/application/DeviceInformationProviderFactory;->getProvider()Lcom/amazon/kcp/application/IDeviceInformationProvider;
+ move-result-object v0
+ invoke-static {v7}, Ljava/util/Arrays;->toString([Ljava/lang/Object;)Ljava/lang/String;
+ move-result-object v2
+ invoke-interface {v0, v2}, Lcom/amazon/kcp/application/IDeviceInformationProvider;->setPidList(Ljava/lang/String;)V
+ invoke-static {v1, v2}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
+
return-object v7
:cond_2

View File

@@ -0,0 +1,74 @@
Kindle for Android
------------------
Kindle for Android uses a different scheme to generate its books specific PIDs than Kindle for PC, Kindle for iPhone/iPad, and standalone Kindles.
Unfortunately, K4Android uses an "account secrets" file that would only be available if the device were jail-broken and even then someone would have to figure out how to decode this secret information in order to reverse the process.
Instead of trying to calculate the correct PIDs for each book from this primary data, "Me" (a commenter who posted to the ApprenticeAlf site) came up with a wonderful idea to simply modify the Kindle 3 for Android application to store the PIDs it uses to decode each book in its "about activity" window. This list of PIDS can then be provided to MobiDeDRM.py, which in its latest incarnations allows a comma separated list of pids to be passed in, to successfully remove the DRM from that book. Effectively "Me" has created an "Unswindle" for the Kindle for Android 3 application!
"Me"'s original patch was for Kindle for Android version 3.0.1.70. Now "Me II" has created a patch for Kindle for Android version 3.7.0.108 and new instructions, since some of the previous steps are no longer necessary.
From the ApprenticeAlf Comments:
"Me II" writes:
Since “Me”s old method for getting PIDs from Kindle for Android is outdated and no longer works with newer versions of the app, I decided Id take a stab at bringing it up to date. It took a little fiddling to get everything working, considering how much has changed since the last patch, but I managed to do it. The process is pretty much identical to “Me”s original instructions, with a few minor changes.
1) You dont need to build apktool from source. You can just grab the binaries from here for whatever OS youre running: http://code.google.com/p/android-apktool/
2) When you sign the rebuilt APK, use the following command instead of the one in the instructions:
jarsigner -verbose -sigalg MD5withRSA -digestalg SHA1 -keystore kindle.keystore kindle3_patched.apk kindle
3) It no longer logs the PIDs, only displays them within the app.
You can get the new patch, for version 3.7.0.108, here: http://pastebin.com/6FN2cTSN
And heres a screenshot of the updated menu: http://imgur.com/BbFVF (sorry for the Japanese, I was too lazy to change my phones language).
Subsequently, "s" wrote:
For others it would be useful to add the keystore generation command into the help file:
keytool -genkey -v -keystore kindle.keystore -alias kindle -keyalg RSA -keysize 2048 -validity 10000
As well as location of prcs on android being (with sdcard):
/mnt/sdcard/Android/data/com.amazon.kindle/files/
"s" also reported success with using the patch on version 3.7.1.8, although I recommend using the 3.7.0.108 version just in case.
"Me"'s original instructions, from the ApprenticeAlf Comments:
"Me" writes:
A better solution seems to create a patched version of the Kindle apk which either logs or displays its PID. I created a patch to both log the pid list and show it in the Kindle application in the about activity screen. The pid list isnt available until the DRMed book has been opened (and the list seem to differ for different books).
To create the patched kindle apk a certificate must be created (http://developer.android.com/guide/publishing/app-signing.html#cert) and the apktool must be build from source (all subprojects) as long as version 1.4.2 isnt released (http://code.google.com/p/android-apktool/wiki/BuildApktool).
These are the steps to pull the original apk from the Android device, uninstall it, create a patched apk and install that (tested on a rooted device, but I think all steps should also work on non-rooted devices):
adb pull /data/app/com.amazon.kindle-1.apk kindle3.apk
adb uninstall com.amazon.kindle
apktool d kindle3.apk kindle3
cd kindle3
patch -p1 < ../kindle3.patch
cd ..
apktool b kindle3 kindle3_patched.apk
jarsigner -verbose -keystore kindle.keystore kindle3_patched.apk kindle
zipalign -v 4 kindle3_patched.apk kindle3_signed.apk
adb install kindle3_signed.apk
kindle3.patch (based on kindle version 3.0.1.70) is available on pastebin:
http://pastebin.com/LNpgkcpP
Have fun!
Comment by me — June 9, 2011 @ 9:01 pm | Reply
Hi me,
Wow! Great work!!!!
With your patch, you have created the equivalent of Unswindle for the Kindle for Android app and it does not even require jailbreaking!
Very nice work indeed!
Comment by some_updates — June 10, 2011 @ 4:28 am | Reply

View File

@@ -0,0 +1,155 @@
diff -ru kindle3.7.0.108_orig/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali kindle3.7.0.108/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali
--- kindle3.7.0.108_orig/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali
+++ kindle3.7.0.108/smali/com/amazon/kcp/application/AndroidDeviceInformationProvider.smali
@@ -43,6 +43,8 @@
.field private security:Lcom/mobipocket/android/library/reader/AndroidSecurity;
+.field private pidList:Ljava/lang/String;
+
.field private totalMemory:J
@@ -78,6 +80,10 @@
.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;
@@ -1242,3 +1248,25 @@
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
\ No newline at end of file
diff -ru kindle3.7.0.108_orig/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali kindle3.7.0.108/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali
--- kindle3.7.0.108_orig/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali
+++ kindle3.7.0.108/smali/com/amazon/kcp/application/IDeviceInformationProvider.smali
@@ -30,3 +30,9 @@
.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
\ No newline at end of file
diff -ru kindle3.7.0.108_orig/smali/com/amazon/kcp/info/AboutActivity.smali kindle3.7.0.108/smali/com/amazon/kcp/info/AboutActivity.smali
--- kindle3.7.0.108_orig/smali/com/amazon/kcp/info/AboutActivity.smali
+++ kindle3.7.0.108/smali/com/amazon/kcp/info/AboutActivity.smali
@@ -493,6 +493,57 @@
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
@@ -539,6 +590,9 @@
invoke-direct {p0}, Lcom/amazon/kcp/info/AboutActivity;->populateDisplayInformation()V
.line 190
+ invoke-direct {p0}, Lcom/amazon/kcp/info/AboutActivity;->populatePIDList()V
+
+ .line 191
return-void
.line 172
diff -ru kindle3.7.0.108_orig/smali/com/amazon/system/security/Security.smali kindle3.7.0.108/smali/com/amazon/system/security/Security.smali
--- kindle3.7.0.108_orig/smali/com/amazon/system/security/Security.smali
+++ kindle3.7.0.108/smali/com/amazon/system/security/Security.smali
@@ -926,6 +926,16 @@
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