DeDRMS.cs
Dieses Script knackt den Copyright Schutz der Tauschbörse
Itones von Appel. Es ist in C# Geschrieben.
|
Script: |
/*****************************************************************************
* DeDRMS.cs: DeDRMS 0.1
*****************************************************************************
* Copyright (C) 2004 Jon Lech Johansen <jon-vl@nanocrew.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
class M4PStream
{
private Rijndael alg;
private BinaryReader br;
private BinaryWriter bw;
private byte [] sbuffer;
private string AtomDRMS = "drms";
private string AtomMP4A = "mp4a";
private string AtomSINF = "sinf";
private string AtomUSER = "user";
private string AtomKEY = "key ";
private string AtomIVIV = "iviv";
private string AtomNAME = "name";
private string AtomPRIV = "priv";
private string AtomSTSZ = "stsz";
private string AtomMDAT = "mdat";
public M4PStream( FileStream fs )
{
br = new BinaryReader( fs );
bw = new BinaryWriter( fs );
sbuffer = br.ReadBytes( Convert.ToInt32( fs.Length ) );
alg = Rijndael.Create();
alg.Mode = CipherMode.CBC;
alg.Padding = PaddingMode.None;
}
byte [] NetToHost( byte [] Input, int Pos, int Count )
{
if( BitConverter.IsLittleEndian )
{
for( int i = 0; i < Count; i++ )
{
Array.Reverse( Input, Pos + (i * 4), 4 );
}
}
return Input;
}
int GetAtomPos( string Atom )
{
byte [] Bytes = Encoding.ASCII.GetBytes( Atom );
for( int i = 0; i < (sbuffer.Length - 3); i++ )
{
if( sbuffer[ i + 0 ] == Bytes[ 0 ] &&
sbuffer[ i + 1 ] == Bytes[ 1 ] &&
sbuffer[ i + 2 ] == Bytes[ 2 ] &&
sbuffer[ i + 3 ] == Bytes[ 3 ] )
{
return i;
}
}
throw new Exception( String.Format( "Atom '{0}' not found", Atom ) );
}
uint GetAtomSize( int Pos )
{
byte [] Bytes = new byte[ 4 ];
Buffer.BlockCopy( sbuffer, Pos - 4, Bytes, 0, 4 );
return BitConverter.ToUInt32( NetToHost( Bytes, 0, 1 ), 0 );
}
byte [] GetAtomData( int Pos, bool bNetToHost )
{
uint Size;
byte [] Bytes;
Size = GetAtomSize( Pos );
Bytes = new byte[ Size - 8 ];
Buffer.BlockCopy( sbuffer, Pos + 4, Bytes, 0, Bytes.Length );
return bNetToHost ? NetToHost( Bytes, 0, Bytes.Length / 4 ) : Bytes;
}
public void Decrypt( byte [] CipherText, int Offset, int Count,
byte [] Key, byte [] IV )
{
MemoryStream ms = new MemoryStream();
ICryptoTransform ct = alg.CreateDecryptor( Key, IV );
CryptoStream cs = new CryptoStream( ms, ct, CryptoStreamMode.Write );
cs.Write( CipherText, Offset, (Count / 16) * 16 );
cs.Close();
ms.ToArray().CopyTo( CipherText, Offset );
}
public byte [] GetUserKey( uint UserID, uint KeyID )
{
byte [] UserKey;
BinaryReader bruk;
string strHome =
Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData );
bool bUnix = Environment.OSVersion.ToString().IndexOf( "Unix" ) != -1;
string strFile = String.Format( "{0}{1}{2}drms{3}{4:X8}.{5:D3}", strHome,
Path.DirectorySeparatorChar, bUnix ? "." : "",
Path.DirectorySeparatorChar, UserID, KeyID );
bruk = new BinaryReader( File.OpenRead( strFile ) );
UserKey = bruk.ReadBytes( Convert.ToInt32( bruk.BaseStream.Length ) );
bruk.Close();
return UserKey;
}
public int [] GetSampleTable()
{
byte [] adSTSZ = GetAtomData( GetAtomPos( AtomSTSZ ), true );
int SampleCount = BitConverter.ToInt32( adSTSZ, 8 );
int [] SampleTable = new int[ SampleCount ];
for( int i = 0; i < SampleCount; i++ )
{
SampleTable[ i ] = BitConverter.ToInt32( adSTSZ, 12 + (i * 4) );
}
return SampleTable;
}
public void DeDRMS()
{
byte [] IV = new byte[ 16 ];
byte [] Key = new byte[ 16 ];
int apDRMS = GetAtomPos( AtomDRMS );
int apSINF = GetAtomPos( AtomSINF );
int apMDAT = GetAtomPos( AtomMDAT );
int [] SampleTable = GetSampleTable();
byte [] adUSER = GetAtomData( GetAtomPos( AtomUSER ), true );
byte [] adKEY = GetAtomData( GetAtomPos( AtomKEY ), true );
byte [] adIVIV = GetAtomData( GetAtomPos( AtomIVIV ), false );
byte [] adNAME = GetAtomData( GetAtomPos( AtomNAME ), false );
byte [] adPRIV = GetAtomData( GetAtomPos( AtomPRIV ), false );
uint UserID = BitConverter.ToUInt32( adUSER, 0 );
uint KeyID = BitConverter.ToUInt32( adKEY, 0 );
string strName = Encoding.ASCII.GetString( adNAME );
byte [] UserKey = GetUserKey( UserID, KeyID );
MD5CryptoServiceProvider MD5 = new MD5CryptoServiceProvider();
MD5.TransformBlock( adNAME, 0, strName.IndexOf( '\0' ), adNAME, 0 );
MD5.TransformFinalBlock( adIVIV, 0, adIVIV.Length );
Decrypt( adPRIV, 0, adPRIV.Length, UserKey, MD5.Hash );
if( Encoding.ASCII.GetString( adPRIV, 0, 4 ) != "itun" )
{
throw new Exception( "Decryption of 'priv' atom failed" );
}
Buffer.BlockCopy( adPRIV, 24, Key, 0, Key.Length );
Buffer.BlockCopy( adPRIV, 48, IV, 0, IV.Length );
for( int i = 0, Pos = apMDAT + 4;
i < SampleTable.Length;
Pos += SampleTable[ i ], i++ )
{
Decrypt( sbuffer, Pos, SampleTable[ i ], Key, IV );
}
Encoding.ASCII.GetBytes( AtomMP4A ).CopyTo( sbuffer, apDRMS );
Encoding.ASCII.GetBytes( AtomSINF.ToUpper() ).CopyTo( sbuffer, apSINF );
bw.Seek( 0, SeekOrigin.Begin );
bw.Write( sbuffer );
}
}
class DeDRMS
{
public static void Main( string [] Args )
{
FileStream fs;
M4PStream m4p;
if( Args.Length != 1 )
{
Console.WriteLine( "Usage: DeDRMS file.m4p" );
return;
}
try
{
fs = new FileStream( Args[ 0 ], FileMode.Open,
FileAccess.Read | FileAccess.Write );
m4p = new M4PStream( fs );
m4p.DeDRMS();
fs.Close();
}
catch( Exception e )
{
Console.WriteLine( "Exception: {0}", e.Message );
return;
}
}
}
|
|