Remove local retrieval of activation bytes. Use audible api. Dramatically reduces program's size
This commit is contained in:
parent
270e2531e2
commit
ff20d777a6
@ -10,57 +10,11 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="..\..\..\..\..\..\Dinah%2527s folder\coding\_NET\Visual Studio 2019\Libation\AaxDecrypter\UNTESTED\BytesCrackerLib\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Dinah.Core\Dinah.Core\Dinah.Core.csproj" />
|
<ProjectReference Include="..\..\Dinah.Core\Dinah.Core\Dinah.Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="BytesCrackerLib\alglib1.dll">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="BytesCrackerLib\audible_byte#4-4_0_10000x789935_0.rtc">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="BytesCrackerLib\audible_byte#4-4_1_10000x791425_0.rtc">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="BytesCrackerLib\audible_byte#4-4_2_10000x790991_0.rtc">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="BytesCrackerLib\audible_byte#4-4_3_10000x792120_0.rtc">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="BytesCrackerLib\audible_byte#4-4_4_10000x790743_0.rtc">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="BytesCrackerLib\audible_byte#4-4_5_10000x790568_0.rtc">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="BytesCrackerLib\audible_byte#4-4_6_10000x791458_0.rtc">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="BytesCrackerLib\audible_byte#4-4_7_10000x791707_0.rtc">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="BytesCrackerLib\audible_byte#4-4_8_10000x790202_0.rtc">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="BytesCrackerLib\audible_byte#4-4_9_10000x791022_0.rtc">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="BytesCrackerLib\ffmpeg.exe">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="BytesCrackerLib\ffprobe.exe">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="BytesCrackerLib\rcrack.exe">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="DecryptLib\AtomicParsley.exe">
|
<None Update="DecryptLib\AtomicParsley.exe">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
|||||||
@ -62,16 +62,18 @@ namespace AaxDecrypter
|
|||||||
public Tags tags { get; private set; }
|
public Tags tags { get; private set; }
|
||||||
public EncodingInfo encodingInfo { get; private set; }
|
public EncodingInfo encodingInfo { get; private set; }
|
||||||
|
|
||||||
public static async Task<AaxToM4bConverter> CreateAsync(string inputFile, string decryptKey, Chapters chapters = null)
|
private Func<Task<string>> getKeyFuncAsync { get; }
|
||||||
|
|
||||||
|
public static async Task<AaxToM4bConverter> CreateAsync(string inputFile, string decryptKey, Func<Task<string>> getKeyFunc, Chapters chapters = null)
|
||||||
{
|
{
|
||||||
var converter = new AaxToM4bConverter(inputFile, decryptKey);
|
var converter = new AaxToM4bConverter(inputFile, decryptKey, getKeyFunc);
|
||||||
converter.chapters = chapters ?? new AAXChapters(inputFile);
|
converter.chapters = chapters ?? new AAXChapters(inputFile);
|
||||||
await converter.prelimProcessing();
|
await converter.prelimProcessing();
|
||||||
converter.printPrelim();
|
converter.printPrelim();
|
||||||
|
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
private AaxToM4bConverter(string inputFile, string decryptKey)
|
private AaxToM4bConverter(string inputFile, string decryptKey, Func<Task<string>> getKeyFunc)
|
||||||
{
|
{
|
||||||
ArgumentValidator.EnsureNotNullOrWhiteSpace(inputFile, nameof(inputFile));
|
ArgumentValidator.EnsureNotNullOrWhiteSpace(inputFile, nameof(inputFile));
|
||||||
if (!File.Exists(inputFile))
|
if (!File.Exists(inputFile))
|
||||||
@ -93,6 +95,7 @@ namespace AaxDecrypter
|
|||||||
|
|
||||||
inputFileName = inputFile;
|
inputFileName = inputFile;
|
||||||
this.decryptKey = decryptKey;
|
this.decryptKey = decryptKey;
|
||||||
|
this.getKeyFuncAsync = getKeyFunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task prelimProcessing()
|
private async Task prelimProcessing()
|
||||||
@ -209,22 +212,12 @@ namespace AaxDecrypter
|
|||||||
|
|
||||||
private int getKey_decrypt(string tempRipFile)
|
private int getKey_decrypt(string tempRipFile)
|
||||||
{
|
{
|
||||||
getKey();
|
decryptKey = getKey();
|
||||||
return decrypt(tempRipFile);
|
return decrypt(tempRipFile);
|
||||||
}
|
}
|
||||||
private void getKey()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Discovering decrypt key");
|
|
||||||
|
|
||||||
Console.WriteLine("Getting file hash");
|
// I am NOT happy about doing async this way. Async needs to be added to Step framework
|
||||||
var checksum = BytesCracker.GetChecksum(inputFileName);
|
string getKey() => getKeyFuncAsync().GetAwaiter().GetResult();
|
||||||
Console.WriteLine("File hash calculated: " + checksum);
|
|
||||||
|
|
||||||
Console.WriteLine("Cracking activation bytes");
|
|
||||||
var activation_bytes = BytesCracker.GetActivationBytes(checksum);
|
|
||||||
decryptKey = activation_bytes;
|
|
||||||
Console.WriteLine("Activation bytes cracked. Decrypt key: " + activation_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int decrypt(string tempRipFile)
|
private int decrypt(string tempRipFile)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,52 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Dinah.Core;
|
|
||||||
using Dinah.Core.Diagnostics;
|
|
||||||
|
|
||||||
namespace AaxDecrypter
|
|
||||||
{
|
|
||||||
public static class BytesCracker
|
|
||||||
{
|
|
||||||
public static string GetChecksum(string aaxPath)
|
|
||||||
{
|
|
||||||
var info = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = BytesCrackerSupportLibraries.ffprobePath,
|
|
||||||
Arguments = aaxPath.SurroundWithQuotes(),
|
|
||||||
WorkingDirectory = Directory.GetCurrentDirectory()
|
|
||||||
};
|
|
||||||
|
|
||||||
// checksum is in the debug info. ffprobe's debug info is written to stderr, not stdout
|
|
||||||
var ffprobeStderr = info.RunHidden().Error;
|
|
||||||
|
|
||||||
// example checksum line:
|
|
||||||
// ... [aax] file checksum == 0c527840c4f18517157eb0b4f9d6f9317ce60cd1
|
|
||||||
var checksum = ffprobeStderr.ExtractString("file checksum == ", 40);
|
|
||||||
|
|
||||||
return checksum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>use checksum to get activation bytes. activation bytes are unique per audible customer. only have to do this 1x/customer</summary>
|
|
||||||
public static string GetActivationBytes(string checksum)
|
|
||||||
{
|
|
||||||
var info = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = BytesCrackerSupportLibraries.rcrackPath,
|
|
||||||
Arguments = @". -h " + checksum,
|
|
||||||
WorkingDirectory = Directory.GetCurrentDirectory()
|
|
||||||
};
|
|
||||||
|
|
||||||
var rcrackStdout = info.RunHidden().Output;
|
|
||||||
|
|
||||||
// example result
|
|
||||||
// 0c527840c4f18517157eb0b4f9d6f9317ce60cd1 \xbd\x89X\x09 hex:bd895809
|
|
||||||
var activation_bytes = rcrackStdout.ExtractString("hex:", 8);
|
|
||||||
|
|
||||||
return activation_bytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,28 +0,0 @@
|
|||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace AaxDecrypter
|
|
||||||
{
|
|
||||||
public static class BytesCrackerSupportLibraries
|
|
||||||
{
|
|
||||||
// GetActivationBytes dependencies
|
|
||||||
// rcrack.exe
|
|
||||||
// alglib1.dll
|
|
||||||
// RainbowCrack files to recover your own Audible activation data (activation_bytes) in an offline manner
|
|
||||||
// audible_byte#4-4_0_10000x789935_0.rtc
|
|
||||||
// audible_byte#4-4_1_10000x791425_0.rtc
|
|
||||||
// audible_byte#4-4_2_10000x790991_0.rtc
|
|
||||||
// audible_byte#4-4_3_10000x792120_0.rtc
|
|
||||||
// audible_byte#4-4_4_10000x790743_0.rtc
|
|
||||||
// audible_byte#4-4_5_10000x790568_0.rtc
|
|
||||||
// audible_byte#4-4_6_10000x791458_0.rtc
|
|
||||||
// audible_byte#4-4_7_10000x791707_0.rtc
|
|
||||||
// audible_byte#4-4_8_10000x790202_0.rtc
|
|
||||||
// audible_byte#4-4_9_10000x791022_0.rtc
|
|
||||||
|
|
||||||
private static string appPath_ { get; } = Path.GetDirectoryName(Dinah.Core.Exe.FileLocationOnDisk);
|
|
||||||
private static string bytesCrackerLib_ { get; } = Path.Combine(appPath_, "BytesCrackerLib");
|
|
||||||
|
|
||||||
public static string ffprobePath { get; } = Path.Combine(bytesCrackerLib_, "ffprobe.exe");
|
|
||||||
public static string rcrackPath { get; } = Path.Combine(bytesCrackerLib_, "rcrack.exe");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -4,6 +4,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AaxDecrypter;
|
using AaxDecrypter;
|
||||||
|
using AudibleApi;
|
||||||
using DataLayer;
|
using DataLayer;
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using Dinah.Core.ErrorHandling;
|
using Dinah.Core.ErrorHandling;
|
||||||
@ -56,9 +57,11 @@ namespace FileLiberator
|
|||||||
if (AudibleFileStorage.Audio.Exists(libraryBook.Book.AudibleProductId))
|
if (AudibleFileStorage.Audio.Exists(libraryBook.Book.AudibleProductId))
|
||||||
return new StatusHandler { "Cannot find decrypt. Final audio file already exists" };
|
return new StatusHandler { "Cannot find decrypt. Final audio file already exists" };
|
||||||
|
|
||||||
var chapters = await downloadChapterNames(libraryBook);
|
var api = await AudibleApiActions.GetApiAsync(libraryBook.Account, libraryBook.Book.Locale);
|
||||||
|
|
||||||
var outputAudioFilename = await aaxToM4bConverterDecrypt(aaxFilename, libraryBook, chapters);
|
var chapters = await downloadChapterNames(libraryBook, api);
|
||||||
|
|
||||||
|
var outputAudioFilename = await aaxToM4bConverterDecrypt(aaxFilename, libraryBook, chapters, api);
|
||||||
|
|
||||||
// decrypt failed
|
// decrypt failed
|
||||||
if (outputAudioFilename == null)
|
if (outputAudioFilename == null)
|
||||||
@ -92,7 +95,23 @@ namespace FileLiberator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> aaxToM4bConverterDecrypt(string aaxFilename, LibraryBook libraryBook, Chapters chapters = null)
|
private static async Task<Chapters> downloadChapterNames(LibraryBook libraryBook, Api api)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var contentMetadata = await api.GetLibraryBookMetadataAsync(libraryBook.Book.AudibleProductId);
|
||||||
|
if (contentMetadata?.ChapterInfo is null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new DownloadedChapters(contentMetadata.ChapterInfo);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> aaxToM4bConverterDecrypt(string aaxFilename, LibraryBook libraryBook, Chapters chapters, Api api)
|
||||||
{
|
{
|
||||||
DecryptBegin?.Invoke(this, $"Begin decrypting {aaxFilename}");
|
DecryptBegin?.Invoke(this, $"Begin decrypting {aaxFilename}");
|
||||||
|
|
||||||
@ -104,7 +123,7 @@ namespace FileLiberator
|
|||||||
.AccountsSettings
|
.AccountsSettings
|
||||||
.GetAccount(libraryBook.Account, libraryBook.Book.Locale);
|
.GetAccount(libraryBook.Account, libraryBook.Book.Locale);
|
||||||
|
|
||||||
var converter = await AaxToM4bConverter.CreateAsync(aaxFilename, account.DecryptKey, chapters);
|
var converter = await AaxToM4bConverter.CreateAsync(aaxFilename, account.DecryptKey, api.GetActivationBytesAsync, chapters);
|
||||||
converter.AppName = "Libation";
|
converter.AppName = "Libation";
|
||||||
|
|
||||||
TitleDiscovered?.Invoke(this, converter.tags.title);
|
TitleDiscovered?.Invoke(this, converter.tags.title);
|
||||||
@ -134,23 +153,6 @@ namespace FileLiberator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Chapters> downloadChapterNames(LibraryBook libraryBook)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var api = await AudibleApiActions.GetApiAsync(libraryBook.Account, libraryBook.Book.Locale);
|
|
||||||
var contentMetadata = await api.GetLibraryBookMetadataAsync(libraryBook.Book.AudibleProductId);
|
|
||||||
|
|
||||||
if (contentMetadata?.ChapterInfo != null)
|
|
||||||
return new DownloadedChapters(contentMetadata.ChapterInfo);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string moveFilesToBooksDir(Book product, string outputAudioFilename)
|
private static string moveFilesToBooksDir(Book product, string outputAudioFilename)
|
||||||
{
|
{
|
||||||
// create final directory. move each file into it. MOVE AUDIO FILE LAST
|
// create final directory. move each file into it. MOVE AUDIO FILE LAST
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
<!-- <PublishSingleFile>true</PublishSingleFile> -->
|
<!-- <PublishSingleFile>true</PublishSingleFile> -->
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
|
||||||
<Version>4.3.0.4</Version>
|
<Version>4.4.0.5</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -10,8 +10,6 @@ namespace ffmpeg_decrypt
|
|||||||
{
|
{
|
||||||
public partial class Form1 : Form
|
public partial class Form1 : Form
|
||||||
{
|
{
|
||||||
public static string resdir { get; } = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "res");
|
|
||||||
|
|
||||||
public Form1()
|
public Form1()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@ -47,10 +45,10 @@ namespace ffmpeg_decrypt
|
|||||||
inputPnl.Enabled = false;
|
inputPnl.Enabled = false;
|
||||||
|
|
||||||
statuslbl.Text = "Getting File Hash...";
|
statuslbl.Text = "Getting File Hash...";
|
||||||
var checksum = await GetChecksum(inputdisplay.Text);
|
var checksum = await RCrack.GetChecksum(inputdisplay.Text);
|
||||||
|
|
||||||
statuslbl.Text = "Cracking Activation Bytes...";
|
statuslbl.Text = "Cracking Activation Bytes...";
|
||||||
var activation_bytes = await GetActivationBytes(checksum);
|
var activation_bytes = await RCrack.GetActivationBytes(checksum);
|
||||||
|
|
||||||
statuslbl.Text = "Converting File...";
|
statuslbl.Text = "Converting File...";
|
||||||
var encodeTo
|
var encodeTo
|
||||||
@ -70,81 +68,6 @@ namespace ffmpeg_decrypt
|
|||||||
statuslbl.Text = "Conversion Complete!";
|
statuslbl.Text = "Conversion Complete!";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<string> GetChecksum(string aaxPath)
|
|
||||||
{
|
|
||||||
Extract("ffprobe.exe");
|
|
||||||
|
|
||||||
var startInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = Path.Combine(resdir, "ffprobe.exe"),
|
|
||||||
Arguments = aaxPath.SurroundWithQuotes(),
|
|
||||||
CreateNoWindow = true,
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
UseShellExecute = false,
|
|
||||||
WorkingDirectory = Directory.GetCurrentDirectory()
|
|
||||||
};
|
|
||||||
|
|
||||||
using var ffp = new Process { StartInfo = startInfo };
|
|
||||||
ffp.Start();
|
|
||||||
|
|
||||||
// checksum is in the debug info. ffprobe's debug info is written to stderr, not stdout
|
|
||||||
var ffprobeStderr = ffp.StandardError.ReadToEnd();
|
|
||||||
|
|
||||||
await Task.Run(() => ffp.WaitForExit());
|
|
||||||
|
|
||||||
ffp.Close();
|
|
||||||
|
|
||||||
// example checksum line:
|
|
||||||
// ... [aax] file checksum == 0c527840c4f18517157eb0b4f9d6f9317ce60cd1
|
|
||||||
var checksum = ffprobeStderr.ExtractString("file checksum == ", 40);
|
|
||||||
|
|
||||||
return checksum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>use checksum to get activation bytes. activation bytes are unique per audible customer. only have to do this 1x/customer</summary>
|
|
||||||
private static async Task<string> GetActivationBytes(string checksum)
|
|
||||||
{
|
|
||||||
Extract("rcrack.exe");
|
|
||||||
|
|
||||||
Extract("alglib1.dll");
|
|
||||||
// RainbowCrack files to recover your own Audible activation data (activation_bytes) in an offline manner
|
|
||||||
Extract("audible_byte#4-4_0_10000x789935_0.rtc");
|
|
||||||
Extract("audible_byte#4-4_1_10000x791425_0.rtc");
|
|
||||||
Extract("audible_byte#4-4_2_10000x790991_0.rtc");
|
|
||||||
Extract("audible_byte#4-4_3_10000x792120_0.rtc");
|
|
||||||
Extract("audible_byte#4-4_4_10000x790743_0.rtc");
|
|
||||||
Extract("audible_byte#4-4_5_10000x790568_0.rtc");
|
|
||||||
Extract("audible_byte#4-4_6_10000x791458_0.rtc");
|
|
||||||
Extract("audible_byte#4-4_7_10000x791707_0.rtc");
|
|
||||||
Extract("audible_byte#4-4_8_10000x790202_0.rtc");
|
|
||||||
Extract("audible_byte#4-4_9_10000x791022_0.rtc");
|
|
||||||
|
|
||||||
var startInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = Path.Combine(resdir, "rcrack.exe"),
|
|
||||||
Arguments = @". -h " + checksum,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
UseShellExecute = false,
|
|
||||||
WorkingDirectory = Directory.GetCurrentDirectory()
|
|
||||||
};
|
|
||||||
|
|
||||||
using var rcr = new Process { StartInfo = startInfo };
|
|
||||||
rcr.Start();
|
|
||||||
|
|
||||||
var rcrackStdout = rcr.StandardOutput.ReadToEnd();
|
|
||||||
|
|
||||||
await Task.Run(() => rcr.WaitForExit());
|
|
||||||
rcr.Close();
|
|
||||||
|
|
||||||
// example result
|
|
||||||
// 0c527840c4f18517157eb0b4f9d6f9317ce60cd1 \xbd\x89X\x09 hex:bd895809
|
|
||||||
var activation_bytes = rcrackStdout.ExtractString("hex:", 8);
|
|
||||||
|
|
||||||
return activation_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessStartInfo.Arguments: use Escaper.EscapeArguments instead of .SurroundWithQuotes()
|
// ProcessStartInfo.Arguments: use Escaper.EscapeArguments instead of .SurroundWithQuotes()
|
||||||
|
|
||||||
// see also: https://stackoverflow.com/questions/4291912/process-start-how-to-get-the-output
|
// see also: https://stackoverflow.com/questions/4291912/process-start-how-to-get-the-output
|
||||||
@ -164,7 +87,7 @@ namespace ffmpeg_decrypt
|
|||||||
|
|
||||||
private static async Task decryptAndSaveFile(string activation_bytes, string inputPath, string outputPath, TextBoxBase debugWindow, EncodeTo encodeTo, int encodeQuality = 80)
|
private static async Task decryptAndSaveFile(string activation_bytes, string inputPath, string outputPath, TextBoxBase debugWindow, EncodeTo encodeTo, int encodeQuality = 80)
|
||||||
{
|
{
|
||||||
Extract("ffmpeg.exe");
|
Resources.Extract("ffmpeg.exe");
|
||||||
|
|
||||||
var fileBase = Path.Combine(outputPath, Path.GetFileNameWithoutExtension(inputPath));
|
var fileBase = Path.Combine(outputPath, Path.GetFileNameWithoutExtension(inputPath));
|
||||||
|
|
||||||
@ -186,7 +109,7 @@ namespace ffmpeg_decrypt
|
|||||||
// nothing in stdout. progress/debug info is in stderr
|
// nothing in stdout. progress/debug info is in stderr
|
||||||
var startInfo = new ProcessStartInfo
|
var startInfo = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = Path.Combine(resdir, "ffmpeg.exe"),
|
FileName = Path.Combine(Resources.resdir, "ffmpeg.exe"),
|
||||||
Arguments = arguments,
|
Arguments = arguments,
|
||||||
CreateNoWindow = true,
|
CreateNoWindow = true,
|
||||||
RedirectStandardError = true,
|
RedirectStandardError = true,
|
||||||
@ -203,24 +126,6 @@ namespace ffmpeg_decrypt
|
|||||||
ffm.Close();
|
ffm.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>extract embedded resource to file if it doesn't already exist</summary>
|
|
||||||
private static void Extract(string resourceName)
|
|
||||||
{
|
|
||||||
// first determine whether files exist already in res dir
|
|
||||||
if (File.Exists(Path.Combine(resdir, resourceName)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// extract embedded resource
|
|
||||||
// this technique works but there are easier ways:
|
|
||||||
// https://stackoverflow.com/questions/13031778/how-can-i-extract-a-file-from-an-embedded-resource-and-save-it-to-disk
|
|
||||||
Directory.CreateDirectory(resdir);
|
|
||||||
using var resource = System.Reflection.Assembly.GetCallingAssembly().GetManifestResourceStream($"{nameof(ffmpeg_decrypt)}.res." + resourceName);
|
|
||||||
using var reader = new BinaryReader(resource);
|
|
||||||
using var file = new FileStream(Path.Combine(resdir, resourceName), FileMode.OpenOrCreate);
|
|
||||||
using var writer = new BinaryWriter(file);
|
|
||||||
writer.Write(reader.ReadBytes((int)resource.Length));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void decryptConvertRb_CheckedChanged(object sender, EventArgs e) => convertGb.Enabled = convertRb.Checked;
|
private void decryptConvertRb_CheckedChanged(object sender, EventArgs e) => convertGb.Enabled = convertRb.Checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
85
_Demos/ffmpeg decrypt/RCrack.cs
Normal file
85
_Demos/ffmpeg decrypt/RCrack.cs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ffmpeg_decrypt
|
||||||
|
{
|
||||||
|
public static class RCrack
|
||||||
|
{
|
||||||
|
public static async Task<string> GetChecksum(string aaxPath)
|
||||||
|
{
|
||||||
|
Resources.Extract("ffprobe.exe");
|
||||||
|
|
||||||
|
var startInfo = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = Path.Combine(Resources.resdir, "ffprobe.exe"),
|
||||||
|
Arguments = aaxPath.SurroundWithQuotes(),
|
||||||
|
CreateNoWindow = true,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
UseShellExecute = false,
|
||||||
|
WorkingDirectory = Directory.GetCurrentDirectory()
|
||||||
|
};
|
||||||
|
|
||||||
|
using var ffp = new Process { StartInfo = startInfo };
|
||||||
|
ffp.Start();
|
||||||
|
|
||||||
|
// checksum is in the debug info. ffprobe's debug info is written to stderr, not stdout
|
||||||
|
var ffprobeStderr = ffp.StandardError.ReadToEnd();
|
||||||
|
|
||||||
|
await ffp.WaitForExitAsync();
|
||||||
|
|
||||||
|
ffp.Close();
|
||||||
|
|
||||||
|
// example checksum line:
|
||||||
|
// ... [aax] file checksum == 0c527840c4f18517157eb0b4f9d6f9317ce60cd1
|
||||||
|
var checksum = ffprobeStderr.ExtractString("file checksum == ", 40);
|
||||||
|
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>use checksum to get activation bytes. activation bytes are unique per audible customer. only have to do this 1x/customer</summary>
|
||||||
|
public static async Task<string> GetActivationBytes(string checksum)
|
||||||
|
{
|
||||||
|
Resources.Extract("rcrack.exe");
|
||||||
|
|
||||||
|
Resources.Extract("alglib1.dll");
|
||||||
|
// RainbowCrack files to recover your own Audible activation data (activation_bytes) in an offline manner
|
||||||
|
Resources.Extract("audible_byte#4-4_0_10000x789935_0.rtc");
|
||||||
|
Resources.Extract("audible_byte#4-4_1_10000x791425_0.rtc");
|
||||||
|
Resources.Extract("audible_byte#4-4_2_10000x790991_0.rtc");
|
||||||
|
Resources.Extract("audible_byte#4-4_3_10000x792120_0.rtc");
|
||||||
|
Resources.Extract("audible_byte#4-4_4_10000x790743_0.rtc");
|
||||||
|
Resources.Extract("audible_byte#4-4_5_10000x790568_0.rtc");
|
||||||
|
Resources.Extract("audible_byte#4-4_6_10000x791458_0.rtc");
|
||||||
|
Resources.Extract("audible_byte#4-4_7_10000x791707_0.rtc");
|
||||||
|
Resources.Extract("audible_byte#4-4_8_10000x790202_0.rtc");
|
||||||
|
Resources.Extract("audible_byte#4-4_9_10000x791022_0.rtc");
|
||||||
|
|
||||||
|
var startInfo = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = Path.Combine(Resources.resdir, "rcrack.exe"),
|
||||||
|
Arguments = @". -h " + checksum,
|
||||||
|
CreateNoWindow = true,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
UseShellExecute = false,
|
||||||
|
WorkingDirectory = Directory.GetCurrentDirectory()
|
||||||
|
};
|
||||||
|
|
||||||
|
using var rcr = new Process { StartInfo = startInfo };
|
||||||
|
rcr.Start();
|
||||||
|
|
||||||
|
var rcrackStdout = rcr.StandardOutput.ReadToEnd();
|
||||||
|
|
||||||
|
await rcr.WaitForExitAsync();
|
||||||
|
rcr.Close();
|
||||||
|
|
||||||
|
// example result
|
||||||
|
// 0c527840c4f18517157eb0b4f9d6f9317ce60cd1 \xbd\x89X\x09 hex:bd895809
|
||||||
|
var activation_bytes = rcrackStdout.ExtractString("hex:", 8);
|
||||||
|
|
||||||
|
return activation_bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
_Demos/ffmpeg decrypt/Resources.cs
Normal file
28
_Demos/ffmpeg decrypt/Resources.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace ffmpeg_decrypt
|
||||||
|
{
|
||||||
|
public static class Resources
|
||||||
|
{
|
||||||
|
public static string resdir { get; } = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "res");
|
||||||
|
|
||||||
|
/// <summary>extract embedded resource to file if it doesn't already exist</summary>
|
||||||
|
public static void Extract(string resourceName)
|
||||||
|
{
|
||||||
|
// first determine whether files exist already in res dir
|
||||||
|
if (File.Exists(Path.Combine(resdir, resourceName)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// extract embedded resource
|
||||||
|
// this technique works but there are easier ways:
|
||||||
|
// https://stackoverflow.com/questions/13031778/how-can-i-extract-a-file-from-an-embedded-resource-and-save-it-to-disk
|
||||||
|
Directory.CreateDirectory(resdir);
|
||||||
|
using var resource = System.Reflection.Assembly.GetCallingAssembly().GetManifestResourceStream($"{nameof(ffmpeg_decrypt)}.res." + resourceName);
|
||||||
|
using var reader = new BinaryReader(resource);
|
||||||
|
using var file = new FileStream(Path.Combine(resdir, resourceName), FileMode.OpenOrCreate);
|
||||||
|
using var writer = new BinaryWriter(file);
|
||||||
|
writer.Write(reader.ReadBytes((int)resource.Length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -66,6 +66,14 @@ namespace inAudibleLite
|
|||||||
Console.SetOut(multiLogger);
|
Console.SetOut(multiLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string aaxPath;
|
||||||
|
public async Task<string> getActivationBytes()
|
||||||
|
{
|
||||||
|
var checksum = await ffmpeg_decrypt.RCrack.GetChecksum(aaxPath);
|
||||||
|
var activationBytes = await ffmpeg_decrypt.RCrack.GetActivationBytes(checksum);
|
||||||
|
return activationBytes;
|
||||||
|
}
|
||||||
|
|
||||||
private async void btnSelectFile_Click(object sender, EventArgs e)
|
private async void btnSelectFile_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var openFileDialog = new OpenFileDialog { Filter = "Audible files (*.aax)|*.aax" };
|
var openFileDialog = new OpenFileDialog { Filter = "Audible files (*.aax)|*.aax" };
|
||||||
@ -75,7 +83,8 @@ namespace inAudibleLite
|
|||||||
this.rtbLog.Clear();
|
this.rtbLog.Clear();
|
||||||
|
|
||||||
this.txtInputFile.Text = openFileDialog.FileName;
|
this.txtInputFile.Text = openFileDialog.FileName;
|
||||||
converter = await AaxToM4bConverter.CreateAsync(this.txtInputFile.Text, this.decryptKeyTb.Text);
|
aaxPath = this.txtInputFile.Text;
|
||||||
|
converter = await AaxToM4bConverter.CreateAsync(this.txtInputFile.Text, this.decryptKeyTb.Text, getActivationBytes);
|
||||||
|
|
||||||
pictureBox1.Image = Dinah.Core.Drawing.ImageReader.ToImage(converter.coverBytes);
|
pictureBox1.Image = Dinah.Core.Drawing.ImageReader.ToImage(converter.coverBytes);
|
||||||
|
|
||||||
@ -90,7 +99,7 @@ namespace inAudibleLite
|
|||||||
|
|
||||||
// only re-process prelim stats if input filename was changed
|
// only re-process prelim stats if input filename was changed
|
||||||
//also pick up new decrypt key, etc//if (this.txtInputFile.Text != converter?.inputFileName)
|
//also pick up new decrypt key, etc//if (this.txtInputFile.Text != converter?.inputFileName)
|
||||||
converter = await AaxToM4bConverter.CreateAsync(this.txtInputFile.Text, this.decryptKeyTb.Text);
|
converter = await AaxToM4bConverter.CreateAsync(this.txtInputFile.Text, this.decryptKeyTb.Text, getActivationBytes);
|
||||||
|
|
||||||
converter.AppName = APP_NAME;
|
converter.AppName = APP_NAME;
|
||||||
converter.SetOutputFilename(this.txtOutputFile.Text);
|
converter.SetOutputFilename(this.txtOutputFile.Text);
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\..\Dinah.Core\Dinah.Core.WindowsDesktop\Dinah.Core.WindowsDesktop.csproj" />
|
<ProjectReference Include="..\..\..\Dinah.Core\Dinah.Core.WindowsDesktop\Dinah.Core.WindowsDesktop.csproj" />
|
||||||
<ProjectReference Include="..\..\AaxDecrypter\AaxDecrypter.csproj" />
|
<ProjectReference Include="..\..\AaxDecrypter\AaxDecrypter.csproj" />
|
||||||
|
<ProjectReference Include="..\ffmpeg decrypt\ffmpeg decrypt.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
Loading…
x
Reference in New Issue
Block a user