Thursday, March 24, 2011

Storing Data in the WAVE File Format

An in-depth look into writing data into WAVE files for the purpose of reading back silently, written by Sierra at Zone-Hacker.net.

Please note the following paper is for informational and educational purposes only. It is to only be used for legitimate programming practices and should not be used to hide malware or evade anti-virus software. That's only two uses for it!

The WAVE file format, known as the Waveform Audio File Format, is a type of audio format standardized by Microsoft and IBM, commonly used as system-sounds in the Windows operating system and used a lot in audio for software, as it is widely supported by programming languages with already "built-in" functions.

The WAV file format is compatible with most operating systems, including Apple's Macintosh, Microsoft's Windows and of course, every one's Linux. The WAV format supports compressed audio and also metadata, meaning they can hold information about the audio itself, such as number of channels, format, sample rate, byte rate, bits per sample and several extra parameters supported by third-party applications and plug-ins.

Now that we know a bit of history about the WAV file, and the basics behind what it's used for - let's talk about how it's structured and put together. I found a great article written by a man named Craig at Stanford University which explains the structure in great detail. It begins like any other file format, with a small ASCII string - "RIFF" which acts as a header for the file.

RIFF - The header, 4 bytes
ChunkSize - the size of the file in bytes following this number, so it will be the entire file minus 8 bytes (RIFF and ChunkSize excluded), 4 bytes.
Format, contains the ASCII letters "WAVE", indicating audio format, 4 bytes.

Now the WAVE file has two "sectors", we'll call them. the "fmt" sector, which contains all the data about the audio being played, it is read by the audio playing software and used to play it using the settings read and codecs indicated in this section. The other sector, is the "data" sector, which contains - you guessed it! Data for the audio playing. So we'll continue with the format now,

"fmt", the sub header for the fmt sector, 4 bytes - in reality doesn't just contain "fmt" but "fmt ", being a space to pad the 4 bytes. (fmt = 3, right? So we add the space to the end of it. It's a wonder why they didn't use a null-byte, actually.)
fmt sector size, this is the size of the rest of the fmt sector, similar to ChunkSize but is only for the fmt sector, 4 bytes.
Audio format, PCM being 1 which is uncompressed audio, 2 bytes.
NumChannels - this is mono or stereo, 1 or 2, 2 bytes.
SampleRate, 4 bytes.
ByteRate, 4 bytes.
BlockAlign, 2 bytes.
BitsPerSample, 2 bytes.
[Optional] ExtraParamSize, 2 bytes - used for displaying information about compression or changes to WAVE format.
[Optional] ExtraParams, unlimited no. bytes. - Possible place to store data.

Now, like I said, the fmt chunk isn't really what we're too worried about. You can grab the fmt chunk from any wave file and copy paste it over, then alter the sector and file sizes accordingly. You could also use the ExtraParams chunk to store data, we'll look into doing that another time - or not at all. We'll see how this turns out.

"data" sector, contains "data", acts as header, 4 bytes.
data sector size, 4 bytes, similar to fmt sector size.
And finally, our much beloved data. It is very similar to End-Of-File data found at the end of executable files for reading back, used in settings or adding a payload to be read and executed in memory. This is where out fun begins.

Now because we can craft the wave file using just a hex editor (I recommend Hex Workshop), you can create a working audio file which will sound like total rubbish but will even play in audio players, so who's to detect it as a virus? Especially if it's encrypted. This is perfect for adding questionable payloads onto the end of a legitimate music file and reading it back using an external application, just add a small ASCII split string, like you would with EOF data, and read back everything after it.

Also, another thing to note, some audio compression formats in WAVE will basically skip parts of data that appear to be "ERROR" and go onto where it looks valid, then play from there - so if you were to take a standard music file from one of your favourite artists that happened to be on your hard-drive, replaced a large portion of the data segment with your payload (with split delimiters on each end, of course), when playing said file it would get to the point where your payload would be, skip it, then continue - usually this will only be a few seconds depending on the size of your payload - so you could replace the end of the audio data so if there person were to play the file, they wouldn't notice!

Expect a function/module written in Visual Basic soon (ReadWAVData/WriteWAVData/ReadWAVResource) and a project example. Also working WAV examples.