Created
August 25, 2017 00:21
-
-
Save MaxMatti/f4c4c4ebe8482ce4ef7ee8d00df1f338 to your computer and use it in GitHub Desktop.
Applies bruteforce to determine an activation key used by audible to encrypt their downloadable audiobook files. Takes 4h CPU-Time on my 3.4 GHz CPU to exhaust the keyspace.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- encoding: utf-8 -*- | |
import datetime | |
from hashlib import sha1 | |
from time import sleep, time | |
from shutil import get_terminal_size | |
from threading import Thread | |
stop = False | |
global_progress = [] | |
def stopping(): | |
global stop | |
stop = True | |
def stopped(): | |
return stop | |
def progress(start_point, current_point, end_point): | |
global global_progress | |
for thread in global_progress: | |
if thread[0] == start_point and thread[2] == end_point: | |
thread[1] = current_point | |
else: | |
global_progress.append([start_point, current_point, end_point]) | |
def guess(start_point, end_point, user_hash): | |
constant = b"\x77\x21\x4d\x4b\x19\x6a\x87\xcd\x52\x00\x45\xfd\x20\xa5\x1d\x67" | |
try: | |
for i in range(start_point, end_point): | |
for j in range(256): | |
progress(start_point * 256, i * 256 + j, end_point * 256) | |
for k in range(256): | |
for l in range(256): | |
tmp = sha1(constant + bytes([i,j,k,l])).digest() | |
if sha1(tmp[:16] + sha1(constant + tmp + bytes([i,j,k,l])).digest()[:16]).digest() == user_hash: | |
print("\r" + " " * (int(get_terminal_size().columns) - 1), end="") | |
print("\r Result: " + str(bytes([i,j,k,l]).hex())) | |
stopping() | |
break | |
if stopped(): | |
return | |
progress(start_point, end_point, end_point) | |
except KeyboardInterrupt: | |
stopping() | |
def timeprinter(start_time): | |
while not stopped(): | |
amount_finished = 0.0 | |
for thread in global_progress: | |
amount_finished += (thread[1] - thread[0]) / (thread[2] - thread[0]) | |
amount_finished /= len(global_progress) | |
print("\r" + " " * (int(get_terminal_size().columns) - 1), end="") | |
if amount_finished > 0: | |
print("\r " + str(int(amount_finished * 1000) / 10) + "% - less than " + str(datetime.timedelta(seconds=(time() - start_time) * (1 - amount_finished) / amount_finished)) + " left.", end="", flush=True) | |
else: | |
print("\r " + str(int(amount_finished * 1000) / 10) + "% - calculating remaining time...", end="", flush=True) | |
sleep(1) | |
def main(): | |
start_time = time() | |
user_hash = input("Enter hash: ") | |
amount_threads = int(input("Enter amount of threads: ")) | |
threads = [] | |
for thread in range(amount_threads): | |
threads.append(Thread(target = guess, args = (int(thread / amount_threads * 256), int((thread + 1) / amount_threads * 256), bytes.fromhex(user_hash)))) | |
threads.append(Thread(target = timeprinter, args = (start_time, ))) | |
for thread in threads: | |
thread.start() | |
for thread in threads: | |
try: | |
thread.join() | |
except KeyboardInterrupt: | |
stopping() | |
for thread in threads: | |
thread.join() | |
if __name__ == '__main__': | |
main() |
Check this out:
https://github.com/MaxMatti/aax-bruteforce
It contains an explanation but also a faster program that does the same.
While investigating I found an even faster way:
- Get your Audible file checksum using ffmpeg like this: ffprobe sample.aax
- Now go to https://audible-tools.kamsker.at/ and enter the checksum there, it gave me my code in under a second. :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What is this "user hash" and how/where do I get it?