View Single Post
  #69  
Old 12-30-2014, 11:25 PM
cw2k cw2k is offline
Junior Member
 
Join Date: Dec 2014
Posts: 15
cw2k is on a distinguished road
Default

Re: Record/Capture/Download/Rip/Save Music from Deezer


Deezer Defuck
=========

Decrypt ya Deezer

1. DL the stream:
It's a Http - Download - I use Proxomitron LogWindow to 'catch the url on the fly however
http://all-streaming-media.com/recor...g-software.htm Replay Media Catcher 5 or VSO Downloader

2. The DL MP3 is somehwo crippled.
-> Workaround: Lower player speed to 50% so it didn't sound like Micky mouse.
However that's not really satisfying

Well some how several MP3-Frames are broken/skipped
a close look.

Winhex ( Datensatz-Darstellungen: 32 418 / Columsize: 209)

Pos MP3-Frame
__________________________
1 Encrypted Frame 1 16 31 46
2 Encrypted Frame 2 17 32 47
3 Encrypted Frame 3 18 33 48
4 Encrypted Frame 4 19 34 49
5 Encrypted Frame 5 20 35 50

n*1

1 UnEncryted Frame 6 21 36
2 UnEncryted Frame 7 22 37
3 UnEncryted Frame 8 23 38
4 UnEncryted Frame 9 24 39
5 UnEncryted Frame 10 25 40
6 UnEncryted Frame 11 26(G)41
7 UnEncryted Frame 12 27 42
8 UnEncryted Frame 13 28 43
9 UnEncryted Frame 14 29 44
A UnEncrypted Frame 15 30 45


Okays so much about static look.

II Let's get the real inside
=============================
Chrome ->F12 Develtools/Src Tab
Shift+Ctrg+F (to search all load source) '.swf

Harvest:
http://cdns-files.deezer.com/swf/cor...-v00340583.swf

SoThink SWF-Decompiler
Deed in coreplayer3-v00340583.swf

Okay finally

coreplayer3-v00340583\dzcoreplayer\crypt\Decrypter.as


...
public static const PART_SIZE:uint = 6144;
...

coreplayer3-v00340583\dzcoreplayer\Streamer.as

Code:
        private function onLoadTimer(event:TimerEvent) : void
        {
            var minChunks:uint;
            var maxChunks:uint;
            var len:uint;
			
            var ba:ByteArray;
            var decryptedData:ByteArray;
			
            var e:* = event;
            var loaded:*    = this._loader.bytesAvailable;
            var decrypted:* = this._decryptedData.length;
			
            if (decrypted < this._bytesTotal)
		
		
				minChunks = Decrypter.PART_SIZE * 2; //0x1800 6144 * 2 -> 12288 0x3000
                maxChunks = Decrypter.PART_SIZE * 3; //0x1800 6144 * 3 -> 18432 0x4800
				
                if ( loaded                      >= minChunks || 
				     this._bytesTotal - decrypted < minChunks)
                {
                    len = Math.min(loaded, maxChunks);  \\ limit loaded to maxChunks
                    if (len > minChunks) \\ only when within minChunks...maxChunks (0x3000..0x4800)
                    {
                        len = len - len % Decrypter.PART_SIZE; // align len to PART_SIZE (0x1800)
                    }
                    ba = new ByteArray();
                    try
                    {
                        this._loader.readBytes(ba, 0, len);
                    }
                    catch (e:Error)
                    {
                        return;
                    }
                    decryptedData = this._decrypter.decryptData(ba);
                    this._decryptedData.writeBytes(decryptedData);
                    this.writeTagsToStream();
....
Well now let's refine the picture

^- that data block that is not magenta is crypted
and so the target for da BlowFishKey CBC decrypter
(that needs to be written)

In short:
Layout it like this
0x0800 Encrypted Block
0x1000 Unencrypted Block

Code:
coreplayer3-v00340583\dzcoreplayer\crypt\Decrypter.as
        private static const INTERVAL_CHUNK:uint = 3;
        private static const CHUNK_SIZE:uint = 2048;
		
        public static const PART_SIZE:uint = 6144;
        private static const IV:String = "000102030405060708090a0b0c0d0e0f";
					
					
        public function setKey(param1:ByteArray) : void
        {
            this._encryptionKey = param1;
            return;
        }// end function

        public function decryptData(param1:ByteArray) : ByteArray
        {
            var L3_ChunkOff:uint = 0;
            var L4_ChunkSize:uint = 0;
            this.kill();
			
			//Set Input Data
            this._source.writeBytes(param1);
            this._source.position = 0;
			
			// Cipher Block Chaining Mode
http://de.wikipedia.org/wiki/Cipher_Block_Chaining_Mode
Code:
            this._decrypter = new CBCMode(
				new BlowFishKey(this._encryptionKey), 
				new NullPad() );
				
			//  Initialisierungsvektor 
            this._decrypter.IV = Hex.toArray(IV);
			
            var L2_Chunks:* = Math.ceil(
										this._source.length / CHUNK_SIZE);
										
            var L5_OutPut:* = new ByteArray();
			
            var L6_ChunkCur:uint = 0;
            while (L6_ChunkCur < L2_Chunks)
            {
                
                L3_ChunkOff  = L6_ChunkCur * CHUNK_SIZE;
				
				// normally it's 'L4_ChunkSize = CHUNK_SIZE'
				// just the tail's different
                L4_ChunkSize = Math.min(
									CHUNK_SIZE, 
									this._source.length - L3_ChunkOff
									);
                L5_OutPut.clear();
                L5_OutPut.writeBytes(
							this._source, L3_ChunkOff, L4_ChunkSize);
							
                if (L6_ChunkCur % INTERVAL_CHUNK == 0 && 
				                L5_OutPut.length == CHUNK_SIZE)
                {
                    this._decrypter.decrypt(L5_OutPut);
                }
				
                // write output
				this._dest.writeBytes(L5_OutPut);
				
				// Inc Count
                L6_ChunkCur = L6_ChunkCur + 1;
            }
			//Ret Decrypted Data
            var _loc_7:* = new ByteArray();
            new ByteArray().writeBytes(this._dest);
            this.kill();
            return _loc_7;
        }// end function
coreplayer3-v00340583\dzcoreplayer\crypt\Decrypter.as
Code:
package dzcoreplayer.crypt
{
    import com.hurlant.crypto.symmetric.*;
^^
Google: "hurlant.crypto.symmetric"
Finally we got it:
http://crypto.hurlant.com/demo/ !!!
Cool there's also a demo so that'll be wonderfull for testing
(before implementing it in well maybe Phython )


So collecting data to decrypt our first DeezerFucked up mp3 frame:
Secret Key
1. Blowfish CBC Padding:NONE
2. IV: 000102030405060708090a0b0c0d0e0f Key: ??
3. Copy first 0x800 bytes from mp3 as hex and past it into Cipher Text:

Hmm only thing that's missing now is the key

Total commander search in decompiled coreplayer3.swf for 'setKey'
onURLBuilt(event:URLBuilderEvent)...
this._decrypter.setKey(event.key);
search: "onURLBuilt"
public class Streamer extends EventDispatcher
{
this._urlBuilder.addEventListener(URLBuilderEvent. URL_BUILT, this.onURLBuilt);


public class URLBuilder extends EventDispatcher
{


public function URLBuilder(param1:uint = 200)
{

this._bd = new BitmapData(500, 8, false);
Strange in 'URLBuilder.as' they build a bitmap to write in data
and read them later
... to be Continued

TestResources

"Aber Bitte mit Sahne"
http://preview-0.deezer.com/stream/2...e4b73801-0.mp3
http://cdn-proxy-2.deezer.com/mobile...ff1fca48738985
http://cdn-proxy-2.deezer.com/mobile...1f ca48738985
Reply With Quote