public static void Strip(string ebookPath, string outputDir, string name, string ccNumber) { if (string.IsNullOrEmpty(outputDir)) { outputDir = Path.GetDirectoryName(ebookPath); } var ebook = new Pdb(ebookPath); var processor = new EReaderProcessor(ebook, name, ccNumber); outputDir = Path.Combine(outputDir, ebook.Filename); if (!Directory.Exists(outputDir)) { Directory.CreateDirectory(outputDir); } string path; for (var i = 0; i < processor.numImagePages; i++) { var img = processor.GetImage(i); path = Path.Combine(outputDir, img.filename); using (var stream = File.Create(path)) stream.Write(img.content, 0, img.content.Length); } var pml = processor.GetText(); path = Path.Combine(outputDir, ebook.Filename + ".pml"); using (var stream = File.CreateText(path)) stream.Write(pml); }
public EReaderPdb(Pdb pdbReader) { this.pdbReader = pdbReader; byte[] headerRawData = pdbReader.GetSection(0); if (headerRawData.Length != 132) { throw new FormatException("Unknown eReader header format."); } using (var stream = new MemoryStream(headerRawData)) { var b = (byte)stream.ReadByte(); if (b > 1) { throw new FormatException(string.Format("Unknown DRM flag {0}", b)); } haveDrm = b == 1; b = (byte)stream.ReadByte(); compressionMethod = (EReaderCompression)b; var buf = new byte[4]; stream.Read(buf, 0, 4); //unknown, should be 0x00000000 buf = new byte[2]; stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } textEncoding = BitConverter.ToUInt16(buf, 0); //should be 2515 or 25152 for cp1251 stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } numberOfSmallFontPages = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } numberOfLargeFontPages = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } nonTextFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } numberOfChapters = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } numberOfSmallFontIndexPages = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } numberOfLargeFontIndexPages = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } numberOfImages = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } numberOfLinks = BitConverter.ToUInt16(buf, 0); b = (byte)stream.ReadByte(); if (b > 1) { throw new FormatException(string.Format("Incorrect Metadata flag {0}", b)); } haveMetadata = b == 1; buf = new byte[3]; stream.Read(buf, 0, 3); //unknown, should be 0 buf = new byte[2]; stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } numberOfFootnotes = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } numberOfSidebars = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } chapterIndexFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } magickValue = BitConverter.ToUInt16(buf, 0); //if (magickValue != 2560) throw new FormatException(string.Format("Unknown Magick Value {0}", magickValue)); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } smallFontPageIndexeFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } largeFontPageIndexeFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } imageDataFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } linksFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } metadataFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); //unknown, should be 0x0000 stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } footnotesFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } sidebarFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) { buf = buf.Reverse(); } lastRecord = BitConverter.ToUInt16(buf, 0); } }
private EReaderProcessor(Pdb pdb, string name, string ccNumber) { if (!(pdb.Filetype == "PNRd" && pdb.Creator == "PPrs")) { throw new FormatException("Invalid eReader file."); } pdbReader = pdb; var eReaderPdb = new EReaderPdb(pdbReader); if (!eReaderPdb.HaveDrm) { throw new InvalidOperationException("File doesn't have DRM or have unknown DRM version: {0}!"); } if (!(eReaderPdb.CompressionMethod == EReaderCompression.Drm1 || eReaderPdb.CompressionMethod == EReaderCompression.Drm2)) { throw new InvalidOperationException($"Unsupported compression method or DRM version: {eReaderPdb.CompressionMethod}!"); } data = pdbReader.GetSection(1); var desEngine = GetDesEngine(data.Copy(0, 8)); var decryptedData = desEngine.TransformFinalBlock(data.Copy(-8), 0, 8); var cookieShuf = decryptedData[0] << 24 | decryptedData[1] << 16 | decryptedData[2] << 8 | decryptedData[3]; var cookieSize = decryptedData[4] << 24 | decryptedData[5] << 16 | decryptedData[6] << 8 | decryptedData[7]; if (cookieShuf < 0x03 || cookieShuf > 0x14 || cookieSize < 0xf0 || cookieSize > 0x200) { throw new InvalidOperationException("Unsupportd eReader format"); } var input = desEngine.TransformFinalBlock(data.Copy(-cookieSize), 0, cookieSize); var r = UnshuffleData(input.SubRange(0, -8), cookieShuf); //using (var stream = new FileStream(pdb.Filename+".eReaderSection1Dump", FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) stream.Write(r, 0, r.Length); var userKeyPart1 = Encoding.ASCII.GetBytes(FixUserName(name)); var userKeyPart2 = Encoding.ASCII.GetBytes(ccNumber.ToCharArray().Copy(-8)); long userKey; using (var stream1 = new MemoryStream(userKeyPart1)) using (var stream2 = new MemoryStream(userKeyPart2)) { userKey = new CRC32().GetCrc32(stream1) & 0xffffffff; userKey = userKey << 32 | new CRC32().GetCrc32(stream2) & 0xffffffff; } var drmSubVersion = (ushort)(r[0] << 8 | r[1]); numTextPages = (ushort)(r[2] << 8 | r[3]) - 1; flags = r[4] << 24 | r[5] << 16 | r[6] << 8 | r[7]; firstImagePage = (ushort)(r[24] << 8 | r[25]); numImagePages = (ushort)(r[26] << 8 | r[27]); if ((flags & ReqdFlags) != ReqdFlags) { throw new InvalidOperationException($"Unsupported flags combination: {flags:x8}"); } var userKeyArray = BitConverter.GetBytes(userKey); if (BitConverter.IsLittleEndian) { userKeyArray = userKeyArray.Reverse(); } desEngine = GetDesEngine(userKeyArray); var encryptedKey = new byte[0]; var encryptedKeySha = new byte[0]; if (eReaderPdb.CompressionMethod == EReaderCompression.Drm1) { if (drmSubVersion != 13) { throw new InvalidOperationException($"Unknown eReader DRM subversion ID: {drmSubVersion}"); } encryptedKey = r.Copy(44, 8); encryptedKeySha = r.Copy(52, 20); } else if (eReaderPdb.CompressionMethod == EReaderCompression.Drm2) { encryptedKey = r.Copy(172, 8); encryptedKeySha = r.Copy(56, 20); } contentKey = desEngine.TransformFinalBlock(encryptedKey, 0, encryptedKey.Length); byte[] checkHash; using (var sha1 = SHA1.Create()) checkHash = sha1.ComputeHash(contentKey); if (!encryptedKeySha.SequenceEqual(checkHash)) { var s = new StringBuilder(); for (var x = 0; x < r.Length - 8; x += 2) { for (var y = 0; y < (x - 20); y += 2) { if (TestKeyDecryption(desEngine, r, x, y)) { s.AppendFormat("keyOffset={0}, hashOffset={1}\n", x, y); } } for (var y = x + 8; y < (r.Length - 20); y += 2) { if (TestKeyDecryption(desEngine, r, x, y)) { s.AppendFormat("keyOffset={0}, hashOffset={1}\n", x, y); } } } if (s.Length > 0) { throw new InvalidDataException("Key and/or KeyHash offset mismatch. Possible values:\n\n" + s); } throw new ArgumentException("Incorrect Name of Credit Card number."); } contentDecryptor = GetDesEngine(contentKey); }
private EReaderProcessor(Pdb pdb, string name, string ccNumber) { if (!(pdb.Filetype == "PNRd" && pdb.Creator == "PPrs")) throw new FormatException("Invalid eReader file."); pdbReader = pdb; var eReaderPdb = new EReaderPdb(pdbReader); if (!eReaderPdb.HaveDrm) throw new InvalidOperationException("File doesn't have DRM or have unknown DRM version: {0}!"); if (!(eReaderPdb.CompressionMethod == EReaderCompression.Drm1 || eReaderPdb.CompressionMethod == EReaderCompression.Drm2)) throw new InvalidOperationException(string.Format("Unsupported compression method or DRM version: {0}!", eReaderPdb.CompressionMethod)); data = pdbReader.GetSection(1); ICryptoTransform desEngine = GetDesEngine(data.Copy(0, 8)); byte[] decryptedData = desEngine.TransformFinalBlock(data.Copy(-8), 0, 8); int cookieShuf = decryptedData[0] << 24 | decryptedData[1] << 16 | decryptedData[2] << 8 | decryptedData[3]; int cookieSize = decryptedData[4] << 24 | decryptedData[5] << 16 | decryptedData[6] << 8 | decryptedData[7]; if (cookieShuf < 0x03 || cookieShuf > 0x14 || cookieSize < 0xf0 || cookieSize > 0x200) throw new InvalidOperationException("Unsupportd eReader format"); byte[] input = desEngine.TransformFinalBlock(data.Copy(-cookieSize), 0, cookieSize); byte[] r = UnshuffData(input.SubRange(0, -8), cookieShuf); //using (var stream = new FileStream(pdb.Filename+".eReaderSection1Dump", FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) stream.Write(r, 0, r.Length); byte[] userKeyPart1 = Encoding.ASCII.GetBytes(FixUserName(name)); byte[] userKeyPart2 = Encoding.ASCII.GetBytes(ccNumber.ToCharArray().Copy(-8)); long userKey; using (var stream1 = new MemoryStream(userKeyPart1)) using (var stream2 = new MemoryStream(userKeyPart2)) { userKey = new CRC32().GetCrc32(stream1) & 0xffffffff; userKey = userKey << 32 | new CRC32().GetCrc32(stream2) & 0xffffffff; } var drmSubVersion = (ushort)(r[0] << 8 | r[1]); numTextPages = (ushort)(r[2] << 8 | r[3]) - 1; flags = r[4] << 24 | r[5] << 16 | r[6] << 8 | r[7]; firstImagePage = (ushort)(r[24] << 8 | r[25]); numImagePages = (ushort)(r[26] << 8 | r[27]); if ((flags & ReqdFlags) != ReqdFlags) throw new InvalidOperationException(string.Format("Unsupported flags combination: {0:x8}", flags)); byte[] userKeyArray = BitConverter.GetBytes(userKey); if (BitConverter.IsLittleEndian) userKeyArray = userKeyArray.Reverse(); desEngine = GetDesEngine(userKeyArray); byte[] encryptedKey = new byte[0], encryptedKeySha = new byte[0]; if (eReaderPdb.CompressionMethod == EReaderCompression.Drm1) { if (drmSubVersion != 13) throw new InvalidOperationException(string.Format("Unknown eReader DRM subversion ID: {0}", drmSubVersion)); encryptedKey = r.Copy(44, 8); encryptedKeySha = r.Copy(52, 20); } else if (eReaderPdb.CompressionMethod == EReaderCompression.Drm2) { encryptedKey = r.Copy(172, 8); encryptedKeySha = r.Copy(56, 20); } contentKey = desEngine.TransformFinalBlock(encryptedKey, 0, encryptedKey.Length); byte[] checkHash = SHA1.Create().ComputeHash(contentKey); if (!encryptedKeySha.IsEqualTo(checkHash)) { var s = new StringBuilder(); for (var x = 0; x < (r.Length - 8); x += 2) { for (var y = 0; y < (x - 20); y += 2) if (TestKeyDecryption(desEngine, r, x, y)) s.AppendFormat("keyOffset={0}, hashOffset={1}\n", x, y); for (var y = x + 8; y < (r.Length - 20); y += 2) if (TestKeyDecryption(desEngine, r, x, y)) s.AppendFormat("keyOffset={0}, hashOffset={1}\n", x, y); } if (s.Length > 0) throw new InvalidDataException("Key and/or KeyHash offset mismatch. Possible values:\n\n" + s); throw new ArgumentException("Incorrect Name of Credit Card number."); } contentDecryptor = GetDesEngine(contentKey); }
public static void Strip(string ebookPath, string outputDir, string name, string ccNumber) { if (string.IsNullOrEmpty(outputDir)) outputDir = Path.GetDirectoryName(ebookPath); var ebook = new Pdb(ebookPath); var processor = new EReaderProcessor(ebook, name, ccNumber); outputDir = Path.Combine(outputDir, ebook.Filename); if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir); string path; for (int i = 0; i < processor.numImagePages; i++) { EReaderImageInfo img = processor.GetImage(i); path = Path.Combine(outputDir, img.filename); using (FileStream stream = File.Create(path)) stream.Write(img.content, 0, img.content.Length); } string pml = processor.GetText(); path = Path.Combine(outputDir, ebook.Filename + ".pml"); using (StreamWriter stream = File.CreateText(path)) stream.Write(pml); }
public EReaderPdb(Pdb pdbReader) { this.pdbReader = pdbReader; byte[] headerRawData = pdbReader.GetSection(0); if (headerRawData.Length != 132) throw new FormatException("Unknown eReader header format."); using (var stream = new MemoryStream(headerRawData)) { var b = (byte)stream.ReadByte(); if (b > 1) throw new FormatException(string.Format("Unknown DRM flag {0}", b)); haveDrm = b == 1; b = (byte)stream.ReadByte(); compressionMethod = (EReaderCompression)b; var buf = new byte[4]; stream.Read(buf, 0, 4); //unknown, should be 0x00000000 buf = new byte[2]; stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); textEncoding = BitConverter.ToUInt16(buf, 0); //should be 2515 or 25152 for cp1251 stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); numberOfSmallFontPages = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); numberOfLargeFontPages = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); nonTextFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); numberOfChapters = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); numberOfSmallFontIndexPages = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); numberOfLargeFontIndexPages = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); numberOfImages = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); numberOfLinks = BitConverter.ToUInt16(buf, 0); b = (byte)stream.ReadByte(); if (b > 1) throw new FormatException(string.Format("Incorrect Metadata flag {0}", b)); haveMetadata = b == 1; buf = new byte[3]; stream.Read(buf, 0, 3); //unknown, should be 0 buf = new byte[2]; stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); numberOfFootnotes = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); numberOfSidebars = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); chapterIndexFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); magickValue = BitConverter.ToUInt16(buf, 0); //if (magickValue != 2560) throw new FormatException(string.Format("Unknown Magick Value {0}", magickValue)); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); smallFontPageIndexeFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); largeFontPageIndexeFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); imageDataFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); linksFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); metadataFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); //unknown, should be 0x0000 stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); footnotesFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); sidebarFirstRecord = BitConverter.ToUInt16(buf, 0); stream.Read(buf, 0, 2); if (BitConverter.IsLittleEndian) buf = buf.Reverse(); lastRecord = BitConverter.ToUInt16(buf, 0); } }