#@@CALIBRE_COMPAT_CODE@@
PLUGIN_NAME = "DeDRM"
-__version__ = '10.0.11'
+__version__ = '10.0.12'
PLUGIN_VERSION_TUPLE = tuple([int(x) for x in __version__.split(".")])
PLUGIN_VERSION = ".".join([str(x)for x in PLUGIN_VERSION_TUPLE])
def getK4Pids(rec209, token, kindleDatabase):
global charMap1
pids = []
-
+ #print(f"Entering getK4Pids with token {token} and kindleDatabase {kindleDatabase}")
try:
# Get the kindle account token, if present
kindleAccountToken = bytearray.fromhex((kindleDatabase[1])['kindle.account.tokens'])
except KeyError:
kindleAccountToken = b''
pass
-
+ extraKindleTokens=kindleDatabase[1].get('kindle.account.secrets',[])
+ extraKindleTokens=[bytearray.fromhex(f) for f in extraKindleTokens]
+ extraKindleTokens.append(kindleAccountToken)
+ #extraKindleTokens=list(set(extraKindleTokens))
try:
# Get the DSN token, if present
DSN = bytearray.fromhex((kindleDatabase[1])['DSN'])
DSN = encode(SHA1(MazamaRandomNumber+encodedIDString+encodedUsername),charMap1)
#print "DSN",DSN.encode('hex')
pass
-
+ extraDSNs=kindleDatabase[1].get('extra.dsns',[])
+ extraDSNs=[bytearray.fromhex(f) for f in extraDSNs]
+ extraDSNs.append(DSN)
if rec209 is None:
- pids.append(DSN+kindleAccountToken)
+ for DSN in extraDSNs:
+ for accToken in extraKindleTokens:
+ pids.append(DSN+accToken)
return pids
# Compute the device PID (for which I can tell, is used for nothing).
table = generatePidEncryptionTable()
- devicePID = generateDevicePID(table,DSN,4)
- devicePID = checksumPid(devicePID)
- pids.append(devicePID)
-
- # Compute book PIDs
-
- # book pid
- pidHash = SHA1(DSN+kindleAccountToken+rec209+token)
- bookPID = encodePID(pidHash)
- bookPID = checksumPid(bookPID)
- pids.append(bookPID)
-
- # variant 1
- pidHash = SHA1(kindleAccountToken+rec209+token)
- bookPID = encodePID(pidHash)
- bookPID = checksumPid(bookPID)
- pids.append(bookPID)
-
- # variant 2
- pidHash = SHA1(DSN+rec209+token)
- bookPID = encodePID(pidHash)
- bookPID = checksumPid(bookPID)
- pids.append(bookPID)
+ for DSN in extraDSNs:
+ devicePID = generateDevicePID(table,DSN,4)
+ devicePID = checksumPid(devicePID)
+ pids.append(devicePID)
+
+ # Compute book PIDs
+ for accToken in extraKindleTokens:
+ # book pid
+ pidHash = SHA1(DSN+accToken+rec209+token)
+ bookPID = encodePID(pidHash)
+ bookPID = checksumPid(bookPID)
+ pids.append(bookPID)
+
+ # variant 1
+ pidHash = SHA1(accToken+rec209+token)
+ bookPID = encodePID(pidHash)
+ bookPID = checksumPid(bookPID)
+ pids.append(bookPID)
+
+ # variant 2
+ pidHash = SHA1(DSN+rec209+token)
+ bookPID = encodePID(pidHash)
+ bookPID = checksumPid(bookPID)
+ pids.append(bookPID)
return pids
typename T::size_type const p(filename.find_last_of('.'));
return p > 0 && p != T::npos ? filename.substr(0, p) : filename;
}
-void enumerateKindleDir(const TCHAR* path,const std::string& outfile,std::set<std::string>* serial_candidates, std::set<std::string>* secret_candidates)
+std::string hexhex(const std::string& st)
+{
+ return hexStr((uint8_t*)st.c_str(), st.size());
+}
+void enumerateKindleDir(const TCHAR* path,const std::string& outfile,std::set<std::string>* serial_candidates, std::set<std::string>* secret_candidates,std::string* k4ifile)
{
WIN32_FIND_DATA ffd;
LARGE_INTEGER filesize;
out.close();
FindClose(hFind);
//\"device_serial_number\":\"
+ // DSN extra.dsns kindle.account.tokens kindle.account.secrets
+ if (k4ifile)
+ {
+ std::ofstream k4i(*k4ifile);
+ if (k4i)
+ {
+ std::cout << "Writing DSN and secrets into " << *k4ifile << std::endl;
+ int nst = 0;
+ k4i << "{";
+ for (auto& serial : working_serials)
+ {
+ switch (nst)
+ {
+ case 0: {
+ k4i << "\"DSN\": \"" << hexhex(serial) << "\"";
+ nst = 1;
+ }; break;
+ case 1: {
+ k4i <<", \"extra.dsns\": [\""<< hexhex(serial)<< "\"";
+ nst = 2;
+ }; break;
+ default: {
+ k4i << ", \"" << hexhex(serial) << "\"";
+ }; break;
+ }
+
+ }
+ if (nst >= 2)
+ {
+
+ k4i << "]";
+ }
+ int kst = 0;
+ for (auto& secret : working_secrets)
+ {
+ if (nst > 0)
+ {
+ k4i << ", ";
+ nst = 0;
+ }
+ switch (kst)
+ {
+ case 0: {
+ k4i << "\"kindle.account.tokens\": \"" << hexhex(secret) << "\"";
+ kst = 1;
+ }; break;
+ case 1: {
+ k4i << ", \"kindle.account.secrets\": [\"" << hexhex(secret) << "\"";
+ kst = 2;
+ }; break;
+ default: {
+ k4i << ", \"" << hexhex(secret) << "\"";
+ }; break;
+ }
+ }
+ if (kst > 0)
+ {
+ k4i << "]";
+ }
+ k4i << "}";
+ }
+
+ }
std::cout << "Note: the below can be copied into text file and used instead of full memory dump. At least one of the secrets is likely to be spurious/incorrect. " << std::endl;
for (auto& serial : working_serials)
{
{
std::cout << "Working secret: \"" << secret << "\""<<std::endl;
}
+
+
return;
}
{
if (argc < 4)
{
- std::cout << "Usage: executable <memdump path> <kindle documents path> <output file>" << std::endl;
+ std::cout << "Usage: executable <memdump path> <kindle documents path> <output file> [<output k4i file(optional)>]" << std::endl;
std::cout << "This program needs accress to Kindle dlls, so it is easiest to run it in the folder with kindle executable or copied dlls" << std::endl;
std::cout << "Please ensure that KRFDynamic.dll is of the appropriate version (currently md5 22ccc712f186e3f03567e2bec2189d6a, kindle 2.7.1(70978))" << std::endl;
return 1;
std::string folder_path = argv[2];
std::string out_path = argv[3];
std::cout << folder_path << std:: endl;
+ std::string k4;
+ std::string* k4file = nullptr;
+ if (argc > 4)
+ {
+ k4 = argv[4];
+ k4file = &k4;
+ }
//this is a bit dumb but I don't know of good ways of flipping between char types
std::basic_string<TCHAR> wfolder_path = std::basic_string<wchar_t>(folder_path.begin(),folder_path.end());
if (hinstLib)
///enumerate folder
printf(("Trying to open %s \n"), argv[1]);
- enumerateKindleDir(wfolder_path.data(),out_path, serial_candidates, secret_candidates);
+ enumerateKindleDir(wfolder_path.data(),out_path, serial_candidates, secret_candidates,k4file);
}
else
{