Vulnerability Development mailing list archives

Re: Audio fingerprinting (was Re: hacksdmi?)


From: Thierry <thierry () PURGE-IT COM>
Date: Mon, 14 Aug 2000 11:36:32 +0100

An Attempt on hacking HackSDMI
 by SnakeByte [ SnakeByte () kryptocrew de ]

 Introduction:

 This is more or less a logfile how I tried to get rid of the protection
from www.hacksdmi.com. When I saw this contest on packetstorm, my first
thought
 was that this is one of the normal break-into-our-server contest, at
which  the server has neither a deamon running or something else :P
 But playing around with watermarks seems interesting, so I tried, and  I
think I succeeded to remove it, so a decoder would just see waste and
 the sound quality did not change to my ears. I don't know if i also
fullfilled the things they want, because I did not submit anything, if I
had
 submitted anything I would not be allowed to publish this, and I think it
is better  to keep information free for everyone than making profit. In
addition to this
 the contest is really unfair, so why should I help them, if they don't
help me ;)  Maybe the language I use is not very technical, but I think
you will understand
 what I say. If you got any comments or want to discuss with me about
this, feel  free to send me a mail. I hope I can help some people with
more endurance to
 make their attack successfull, but as I will mention later, in my opinion
the  watermark will be completely cracked, when they remove this stuff and
the contest
 is more fair.


 The Log:

 First of all SDMI is playing not fair, by blowing the downloads  to 50 MB
a piece a lot of people are not able to take part in the
 challenge, because they can't pay for such a download or just have a
modem which means they have to download 10h. The next problem provided by
 the huge files is that i had to search some hours for a hexeditor which
is  able to view them ( NEXT-Soft Hex-Editor 2000 did it well ).
 Ok, let's see what is inside the zip file ?  A readme and three wav
files. Ok, while downloading some descriptions
 of the RIFF WAV Format I took a look at the readme. Not nice,  they just
tell me what this files are and nothing about the technique they
 used. Seems like another security by obscurity challenge. This sucks !
Why do they not look for a real protection, instead of just trying to
 hide some things. Sure it is not easy to get rid of it, but this is just
because  they provide no tool to check ( so we could disasm it and see
what it checks for ),
 they files are that huge and we got just 3 to analyze. Ok, let's see what
we  got here.

Technology A

 Files:
 samp1a.wav   - 21397736 Bytes    - Without Watermark
 samp2a.wav   - 21397548 Bytes    - Watermarked Version of 1a
 samp3a.wav   - 21405740 Bytes    - Watermarked example without clean
counterpart


 Ok, first of all we should have a look at samp1a.wav and samp2a.wav .
He, whats this ? The version without the watermark is bigger than the one
 without. How can this happen ? By the time I asked this question, there
was  noone around to answer ( Fear and Loathing rocks ).
 So I took my Hexeditor and took a look at both. We found a small
signature at the end of sample 1a. ( 188 Bytes )

 ------8<-------------
 4C4953544C000000494E464F494352440B000000323030302D30392D3038
 000049454E47130000004172636869766520546563686E6F6C6F67790000
 4953465410000000536F756E6420466F72676520342E3500637565201C00
 000001000000010000000000000064617461000000000000000000000000
 4C4953543C0000006164746C6C747874140000000100000000A051007267
 6E2000000000000000006C61626C14000000010000005265636F72642054
 616B652030303100

 LISTL   INFOICRD    2000-09-08  IENG    Archive Technology
 ISFT    Sound Forge 4.5 cue       data LIST> adtlltxt   Q
 rgn labl      Record Take 001
 ------8<-------------

 I quickly removed this stuff to have 2 files which are equal in size.
 Ok, let's have a look at the other differences of the two files.
 The first difference is at offset 00000004h. A quick glance at the
 wav file format description tell us that this double word is the lenght
of
 the file. When we subtract the both values, we see that the difference is

 exactly 0bch Bytes ( 188d Bytes ) so we can let this difference as it is.

 ( This is no Watermark, we could add some of our data, at the end to
 remove this as well *g* ) Ok, we do a little comparison of both files:

  | Offset |  Value File1 |  Value File2  |  Difference  |
  |--------+--------------+---------------+--------------|
  |  4eh   |     a8h      |      a7h      |      +1      |
  |  50h   |     0eh      |      0fh      |      +1      |
  |  56h   |     a4h      |      a5h      |      +1      |
  |  58h   |     4ah      |      49h      |      -1      |
  |  6eh   |     71h      |      70h      |      +1      |
  |  74h   |     93h      |      94h      |      +1      |
  |  80h   |     ebh      |      ech      |      +1      |
  |  86h   |     5ah      |      59h      |      -1      |
  | [...]  |    [...]     |     [...]     |     [...]    |

 We quickly notice that the values always differ by +1, 0 or -1.
 This means they just influenced the last bit, the least significant
 bit. Thats exactly what I expected *eg*

 The Format Chunk tells us that this is a stereo recorded file.
 44100 Hz is the sample rate with 176400 Bytes per second in 16 Bit
 stereo with 16 Bits per Sample. ( I also don't know what this all
 means but we'll see if we need this. )

 Let's have another look at the wav file format to see what exactly
 they changed.

 At offset 24h starts the data section. So we are right inside ;)
 So offset 2ch is the beginning of the real data. This is what is changed.

 Quote from
http://technology.niagarac.on.ca/courses/comp630/WavFileFormat.html :

 "The data is a value from 0x00 to 0xFF. In the example above 0x80 would
  represent "0" or silence on the output since the DAC used to playback
samples
  is a bipolar device (i.e. a value of 0x00 would output a negative
voltage and
  a value of 0xFF would output a positive voltage at the output of the DAC
on the
  sound card)."

 Ok, so if we change one of the least significant bits here, the listener
 will not notice anything. So we simply change the LSB to a 0 or 1 at
random,
 an we will have wiped out at least 50% of the watermark and we have
changed
 some other values where a watermark might have been ( we don't know how
they
 hide it, it may be different on every encoded file, thats why it sucks
that they
 don't have provided any technical information )

 Hmm, whats this ? At offset 23324d ( 5b1ch ) the differences are 3h.

             offset 23324d : 56h --> 59h
             offset 23326d : EEh --> F1h
             offset 23328d : EDh --> F0h
             offset 23330d : 60h --> 63h
             offset 23336d : 4h --> 1h
             offset 23338d : 7Fh --> 7Ch

 Then there is a difference of 5 :

             offset 23340d : 90h --> 8Bh
             offset 23342d : 18h --> 13h

 And finally changes between 3 and 5

             offset 23344d : B6h --> B3h
             offset 23346d : 45h --> 41h
             offset 23352d : 84h --> 86h
             offset 23354d : C9h --> CCh
             offset 23356d : C1h --> C3h
             offset 23368d : 45h --> 49h
             offset 23370d : A9h --> AEh
             offset 23372d : F1h --> F6h
             offset 23374d : CBh --> D1h

 Ok whats happening here ? Seems as if they do no longer only change
 the least significant bit. They change the last 5 bits.

             offset 24316d : 76h --> D6h
             offset 24318d : 90h --> 40h
             offset 24320d : 2Dh --> 36h
             offset 24322d : 29h --> F3h
             offset 24324d : E5h --> 7Eh
             offset 24326d : A4h --> 85h
             offset 24328d : 61h --> E7h

 Now it seems as if they change the values completely. This confuses me a
bit.
 No, this confuses me a byte... a word !! This may be the solution.
 The data is stored in words. The always change the lower part of the
word,
 never the upper part. I'll have a look in the wav reference again and go
on
 writing later.

 Ok, this is still the same section and there are no hints in the
reference
 that the data is stored there in a different way. I took another wav file

 I got on my computer and changed the second byte of several words
 ( The Microsoft Sound.wav ) I heard no difference exept on the places
where
 has been an 80h ( silence ). If you change them you will hear a
difference,
 because a knack inside the silence is very easy to hear ;)
 So me might want to change the second byte of every word. How could we do
this ?
 When we always change the second byte to a random number the sound
quality would
 go to hell. I think that it will be ok, to change the last 5 Bytes. ( 0 -
7 )
 When we generate a random number ( 1-7 ) and make an exlusive or with
this value
 we will remove the watermark so much that it will be no longer visible.
 Why do we need a random value ? Since we don't know how they generate the
watermark
 ( as I said earlyer this contest is not fair :P ) we can't use a static
value,
 otherwise they may come and say, heh they just added 1 to each word, if
you remove
 it you see our watermark. This way they can't say, if you add 1 to the
first,
 subtract 2 of the second, add 4 to the next and subtract 2 of the ... etc

 If i would do something like this, I could transform the bible into an
diabolic
 manifest ;)

 Example:
   76h  = 1110110b
   xor
    1   = 1110111b   -->  77h
    2   = 1110100b   -->  74h
    3   = 1110101b   -->  75h
    4   = 1110010b   -->  72h
    5   = 1110011b   -->  73h
    6   = 1110000b   -->  70h
    7   = 1110001b   -->  71h

 This way we just change every word by 0,0107 percent. I don't think that
anyone will
 hear this ;)

 Now we write a little program which exactly does this. We read the data
section word by
 word, change the second byte and write it back.

 ---------8<-------------------
.486p
locals
jumps
.model flat,STDCALL

 extrn          CreateFileA:PROC   ;Open files
 extrn          ExitProcess:PROC   ;termination of program
 extrn             ReadFile:PROC   ;read a file..
 extrn          CloseHandle:PROC   ;closing files
 extrn       SetFilePointer:PROC   ;move filepointer
 extrn            WriteFile:PROC   ;changing files
 extrn          MessageBoxA:PROC   ;communikation *g*
 extrn         GetTickCount:PROC   ;random number


.DATA
  Filename  db 'samp2a.wav',0       ;our target
  Filename2 db 'newsamp2a.wav',0

  Fine      db 'Ok',0
  MSG       db 'we did it',0

  FirstChunk equ       2ch          ;size till we are in the data section
  FileSize   equ 21397548d - FirstChunk

  Handle  dd ?
  Read    dd ?
  Write   dd ?
  Handle2 dd ?


  Filemem db 30h dup (?)           ;buffer to read file

.CODE
code:
  push 0
  push 080h                        ;normal attribs
  push 3                           ;open an existing file
  push 0
  push 0
  push 0C0000000h                  ;read + write
  push offset Filename
  Call CreateFileA                 ;open target
  mov Handle,eax
  cmp eax, 0FFFFFFFFh
  je End

  push 0
  push offset Read                 ;number of bytes read..
  push 2ch                         ;how many bytes to read
  push offset Filemem              ;where to store ?
  push Handle                      ;filehandle
  Call ReadFile
                                   ;we read 2ch to get to the start of the

                                   ;real data ( i am too lazy to use the
                                   ;setfilepointer

  push 0                           ;open the output file
  push 080h                        ;normal attribs
  push 2                           ;open an existing file
  push 0
  push 0
  push 0C0000000h                  ;read + write
  push offset Filename2            ;output file
  Call CreateFileA
  mov Handle2,eax

  push 0
  push offset Write
  push 2ch                         ;write the first stub to the output
file
  push offset Filemem
  push Handle2
  Call WriteFile


ChangeIt:
 mov ebx, offset Filemem           ;point to the second byte

  push 0
  push offset Read
  push 100d
  push offset Filemem
  push Handle
  Call ReadFile

  cmp dword ptr [Read],0           ;we do this to the end of the file
  je End_Close_File

  mov ecx, 100d
  ChangeIt2:
  push ecx

   mov al, byte ptr [ebx]           ;get the byte we want to change in eax

   cmp al, 80h                      ;silence ?
   je NextWord
   call GetRand                     ;generate a random number in ecx
   xor eax, ecx
   mov byte ptr [ebx], al           ;save an write to file

NextWord:
  add ebx, 2h

  pop ecx
  loop ChangeIt2

  push 0
  push offset Write
  push dword ptr [Read]
  push offset Filemem
  push Handle2
  Call WriteFile

  jmp ChangeIt


End_Close_File:
  push Handle
  Call CloseHandle
  push Handle2
  Call CloseHandle

Success:
  push 10h
  push offset Fine
  push offset MSG
  push 0
  call MessageBoxA

End:
  push 0h
  call ExitProcess
  jmp End


GetRand:        ;generate a random number between 1 and 7
                ;in ecx
push eax
push edx

 call GetTickCount
 add eax, ebx   ;generate pseudo-random number ;P
 add eax, ecx   ;good enough for this task
 xor eax, edx
 add eax, ebp

 push 7h
 pop ecx
 xor edx, edx   ;clean edx ( needed to be able to divide later )
 div ecx        ;Random Numer is in EAX
 xchg eax, ecx
 inc ecx

pop edx
pop eax


ret

Ends
End code
 ---------8<-------------

 Well, it works :) Seems as if we beat technology A ...




Technology B

 Baah, it is the same fucking song, not very creative, let's see
 if the protection is something better.
 Hmm.. here they also just changed the second byte, so me are able to use
 the same "attack".. strange, did I misunderstood something, let's take
another
 look at the readme..

 "You must remove or alter the audio watermark in eight consecutive 15
second windows."

 Ok, I think we did this.

 "The initial test of your attack will only be considered a success if the
decoder is
  not able to detect any of the watermark bits."

 Hmm.. this confuses me, "any of the watermark bits" .. do they mean we
should
 change every _Bit_ of the watermark ??? Heh, this is not possible without

 an analysis of the decoder. We don't know how they hide and we don't know

 what they hide... If we got more samples, we could try a to find common
 things, we could try to detect the algorithm. But this way ?
 If the decrypter detect some Bits of the Original Watermark, they are
 no real proof that there has ever been a watermark. If we take the
original
 file and change the second byte by XOR-ing it with 0FFh, the decoder
would
 also detect lots of Bits of the watermark.
 Just take a look at the last bit of a byte. We set this bit to 1 and
 see how many letters there are, which have it set.. ;)

 256 / 2 ( all uneven numbers ) = 128

 If they would complain we need to remove all Bits, we change our code
this way:

 ----8<------
   mov al, byte ptr [ebx]           ;get the byte we want to change in eax

   xor al, 0ffh                     ;xor with 0ffh
   mov byte ptr [ebx], al           ;save an write to file
 ----8<------

 And remove the GetRand Procedure ( no longer nessecairy ) This way I hear
a
 small difference, we could get it better, if we would have at least 2
originals
 and 2 watermarked examples, to check for regularities in the way they
change
 the bytes. Then we could guess about their watermark algorithm and just
defeat the
 right bits. Then we would be able to create a more effektive attack. This
way, we could
 make a guess, submit the file, wait some days for the answer and then go
on... not
 really worth thinking about this.

 "In addition, the sound quality of the attacked sample cannot have been
degraded
  below that of MP3 encoding at 64 Kbps for a stereo signal or a
comparative
 analysis using PEAQ."

 Dont really know what they mean by this, but I also think we succeeded in
this,
 the sound quality does not change, and if it would, we just decrease the
 random value to get it better :)

 Same applies to Technology C, here they always just changed the last
Bit...
 This whole thing starts to get boring. I will stop my analysis here,
because trying
 to guess byte patterns is not very exciting ;) I hope they choose on of
the technologys
 and I can sometime get my hand on more examples, because if I would think
I have found
 something I can't really test it that way. So whatever method they used,
if you just
 put some noise above it you can hide or remove the watermark, but to
write down a complete
 analysis, we either need the player ( which decodes the watermark ) and
reverse engineer it,
 or we would need more examples to generate some statistics. If they
decide for one
 of the technologys they also have nessecairily to provide us both ;)
 So as far as I see the situation, they can tell their customers after the
contest, that
 it is save, but when they release the things it just takes some weeks
until it is broken.
 Thats all for now.


Current thread: