Transferring Data Between Computers Using Audio on Windows 11

I0veD
cyber security researcher·
·
5 min read
Article

LINK: ‣


send:

#include <stdio.h>
#include <windows.h>
#include <math.h>

#pragma comment(lib, "winmm.lib")

#define AUDIO_BITS_PER_SAMPLE 16
#define AUDIO_SAMPLE_RATE 8000

#define TONE_LENGTH_MS 50

#define TRANSMISSION_START_FREQUENCY 2000
#define BIT_TONE_FREQUENCY_ON 600
#define BIT_TONE_FREQUENCY_OFF 800
#define TRANSMISSION_END_FREQUENCY 1500
#define BIT_TONE_FREQUENCY_NEXT 1200

struct WaveHeaderStruct
{
DWORD dwChunkID;
DWORD dwChunkSize;
DWORD dwFormat;

DWORD dwSubChunk1ID;
DWORD dwSubChunk1Size;
WORD wAudioFormat;
WORD wNumChannels;
DWORD dwSampleRate;
DWORD dwByteRate;
WORD wBlockAlign;
WORD wBitsPerSample;

DWORD dwSubChunk2ID;
DWORD dwSubChunk2Size;

};

FILE* pGlobal_WaveFile = NULL;
DWORD dwGlobal_TotalWaveDataLength = 0;
WaveHeaderStruct Global_WaveHeader;

DWORD InitialiseWaveFile(char* pFilePath)
{
// create output file
errno_t err = fopen_s(&pGlobal_WaveFile, pFilePath, "wb");
if (err != 0 || pGlobal_WaveFile == NULL)
{
return 1;
}

// reset data length
dwGlobal_TotalWaveDataLength = 0;

// generate initial wave header
memset((void*)&amp;Global_WaveHeader, 0, sizeof(Global_WaveHeader));
Global_WaveHeader.dwChunkID = 0x46464952;
Global_WaveHeader.dwChunkSize = 36;
Global_WaveHeader.dwFormat = 0x45564157;
Global_WaveHeader.dwSubChunk1ID = 0x20746D66;
Global_WaveHeader.dwSubChunk1Size = 16;
Global_WaveHeader.wAudioFormat = 1;
Global_WaveHeader.wNumChannels = 1;
Global_WaveHeader.dwSampleRate = AUDIO_SAMPLE_RATE;
Global_WaveHeader.dwByteRate = AUDIO_SAMPLE_RATE * (AUDIO_BITS_PER_SAMPLE / 8);
Global_WaveHeader.wBlockAlign = AUDIO_BITS_PER_SAMPLE / 8;
Global_WaveHeader.wBitsPerSample = AUDIO_BITS_PER_SAMPLE;
Global_WaveHeader.dwSubChunk2ID = 0x61746164;
Global_WaveHeader.dwSubChunk2Size = 0;

// write header to file
fwrite((void*)&amp;Global_WaveHeader, sizeof(Global_WaveHeader), 1, pGlobal_WaveFile);

return 0;

}

DWORD CloseWaveFile()
{
// move back to the start of the file
rewind(pGlobal_WaveFile);

// store total data length in wave header
Global_WaveHeader.dwChunkSize += dwGlobal_TotalWaveDataLength;
Global_WaveHeader.dwSubChunk2Size += dwGlobal_TotalWaveDataLength;

// write the updated header
fwrite((void*)&amp;Global_WaveHeader, sizeof(Global_WaveHeader), 1, pGlobal_WaveFile);

// close file handle
fclose(pGlobal_WaveFile);

return 0;

}

DWORD GenerateTone(DWORD dwFrequency, DWORD dwDuration)
{
DWORD dwSampleCount = 0;
DWORD dwTotalSize = 0;
double dPeriod = 0;
WORD* pwSampleList = NULL;

// set initial values
dwSampleCount = (AUDIO_SAMPLE_RATE * dwDuration) / 1000;
dwTotalSize = dwSampleCount * sizeof(WORD);
dPeriod = AUDIO_SAMPLE_RATE / (double)dwFrequency;

// allocate memory for audio samples
pwSampleList = (WORD*)malloc(dwTotalSize);
if (pwSampleList == NULL)
{
	return 1;
}


listen:

#include <stdio.h>
#include <windows.h>
#include <math.h>

#pragma comment(lib, "winmm.lib")

#define AUDIO_BITS_PER_SAMPLE 16
#define AUDIO_SAMPLE_RATE 8000

#define TRANSMISSION_START_FREQUENCY 2000
#define BIT_TONE_FREQUENCY_ON 600
#define BIT_TONE_FREQUENCY_OFF 800
#define TRANSMISSION_END_FREQUENCY 1500
#define BIT_TONE_FREQUENCY_NEXT 1200

#define TONE_THRESHOLD 500

DWORD dwGlobal_TransmissionStarted = 0;
DWORD dwGlobal_BitsReceived = 0;
BYTE bGlobal_RecvBits[8];
DWORD dwGlobal_LastToneType = 0;

// 1 second audio buffer
BYTE bGlobal_AudioBuffer[AUDIO_SAMPLE_RATE * sizeof(WORD)];

double CalculateToneMagnitude(short *pSamples, DWORD dwSampleCount, DWORD dwTargetFrequency)
{
DWORD dwK = 0;
double dScalingFactor = 0;
double dW = 0;
double dSine = 0;
double dCosine = 0;
double dCoeff = 0;
double dQ0 = 0;
double dQ1 = 0;
double dQ2 = 0;
double dMagnitude = 0;

// set initial values for goertzel algorithm
dScalingFactor = (double)dwSampleCount / 2.0;
dwK = (DWORD)(0.5 + (((double)dwSampleCount * (double)dwTargetFrequency) / AUDIO_SAMPLE_RATE));
dW = (2.0 * 3.14159 * (double)dwK) / (double)dwSampleCount;
dSine = sin(dW);
dCosine = cos(dW);
dCoeff = 2.0 * dCosine;

// process all samples
for(DWORD i = 0; i &lt; dwSampleCount; i++)
{
	// process current sample
	dQ0 = (dCoeff * dQ1) - dQ2 + pSamples[i];
	dQ2 = dQ1;
	dQ1 = dQ0;
}

// calculate magnitude
dMagnitude = (double)sqrtf((float)((dQ1 * dQ1) + (dQ2 * dQ2) - (dQ1 * dQ2 * dCoeff)));
dMagnitude /= 100;

return dMagnitude;

}

DWORD ProcessSamples()
{
BYTE bRecvByte = 0;
DWORD dwSamplesRemaining = 0;
DWORD dwCurrSampleIndex = 0;
DWORD dwCurrChunkSize = 0;
short *pCurrSamplePtr = NULL;
double dFrequencySignal_TransmissionStart = 0;
double dFrequencySignal_TransmissionStart2 = 0;
double dFrequencySignal_TransmissionEnd = 0;
double dFrequencySignal_NextBit = 0;
double dFrequencySignal_BitOn = 0;
double dFrequencySignal_BitOff = 0;
double dStrongestTone = 0;
DWORD dwStrongestToneType = 0;

// process current samples
dwSamplesRemaining = sizeof(bGlobal_AudioBuffer) / sizeof(WORD);
dwCurrSampleIndex = 0;
for(;;)
{
	// check of all samples have been processed
	if(dwSamplesRemaining == 0)
	{
		// finished
		break;
	}

	// calculate current chunk size (25ms)
	dwCurrChunkSize = (AUDIO_SAMPLE_RATE / 40);
	if(dwSamplesRemaining &lt; dwCurrChunkSize)
	{
		dwCurrChunkSize = dwSamplesRemaining;
	}

	// get current sample position
	pCurrSamplePtr = (short*)&amp;bGlobal_AudioBuffer[dwCurrSampleIndex * sizeof(WORD)];

	// check if a transmission is already in progress
	if(dwGlobal_TransmissionStarted == 0)
	{
		// no transmission - check if a new one is starting
		dFrequencySignal_TransmissionStart = CalculateToneMagnitude(pCurrSamplePtr, dwCurrChunkSize, TRANSMISSION_START_FREQUENCY);
		if(dFrequencySignal_TransmissionStart &gt;= TONE_THRESHOLD)
		{
			// new data transmission detected
			dwGlobal_BitsReceived = 0;
			dwGlobal_LastToneType = TRANSMISSION_START_FREQUENCY;
			dwGlobal_TransmissionStarted = 1;
		}
	}
	else
	{
		// a transmission is already in progress - get next tone
		dFrequencySignal_TransmissionStart = CalculateToneMagnitude(pCurrSamplePtr, dwCurrChunkSize, TRANSMISSION_START_FREQUENCY);
		dFrequencySignal_BitOn = CalculateToneMagnitude(pCurrSamplePtr, dwCurrChunkSize, BIT_TONE_FREQUENCY_ON);
		dFrequencySignal_BitOff = CalculateToneMagnitude(pCurrSamplePtr, dwCurrChunkSize, BIT_TONE_FREQUENCY_OFF);
		dFrequencySignal_NextBit = CalculateToneMagnitude(pCurrSamplePtr, dwCurrChunkSize, BIT_TONE_FREQUENCY_NEXT);
		dFrequencySignal_TransmissionEnd = CalculateToneMagnitude(pCurrSamplePtr, dwCurrChunkSize, TRANSMISSION_END_FREQUENCY);

		// check for the strongest tone
		dStrongestTone = 0;
		dwStrongestToneType = 0;
		if(dFrequencySignal_TransmissionStart &gt; dStrongestTone)
		{
			dStrongestTone = dFrequencySignal_TransmissionStart;
			dwStrongestToneType = TRANSMISSION_START_FREQUENCY;
		}
		if(dFrequencySignal_BitOn &gt; dStrongestTone)
		{
			dStrongestTone = dFrequencySignal_BitOn;
			dwStrongestToneType = BIT_TONE_FREQUENCY_ON;
		}
		if(dFrequencySignal_BitOff &gt; dStrongestTone)
		{
			dStrongestTone = dFrequencySignal_BitOff;
			dwStrongestToneType = BIT_TONE_FREQUENCY_OFF;
		}
		if(dFrequencySignal_NextBit &gt; dStrongestTone)
		{
			dStrongestTone = dFrequencySignal_NextBit;
			dwStrongestToneType = BIT_TONE_FREQUENCY_NEXT;
		}
		if(dFrequencySignal_TransmissionEnd &gt; dStrongestTone)
		{
			dStrongestTone = dFrequencySignal_TransmissionEnd;
			dwStrongestToneType = TRANSMISSION_END_FREQUENCY;
		}

		// ensure at least one frequency is above the minimum threshold
		if(dStrongestTone &lt; TONE_THRESHOLD)
		{
			if(dwGlobal_BitsReceived != 0)
			{
				printf(&quot;\n** DATA CORRUPT - CANCELLED TRANSMISSION **\n&quot;);
			}
			dwGlobal_TransmissionStarted = 0;
		}
		else
		{
			// check if the tone has changed
			if(dwStrongestToneType != dwGlobal_LastToneType)
			{
				// new tone detected
				if(dwStrongestToneType == TRANSMISSION_START_FREQUENCY)
				{
					// found &quot;transmission start&quot; tone but already receiving data
					if(dwGlobal_BitsReceived != 0)
					{
						printf(&quot;\n** DATA CORRUPT - CANCELLED TRANSMISSION **\n&quot;);
					}

					dwGlobal_TransmissionStarted = 0;
				}
				else if(dwStrongestToneType != BIT_TONE_FREQUENCY_NEXT)
				{
					// check if this is a data bit
					if(dwStrongestToneType == BIT_TONE_FREQUENCY_ON || dwStrongestToneType == BIT_TONE_FREQUENCY_OFF)
					{
						if(dwGlobal_BitsReceived == 0)
						{
							// receiving first data bit
							printf(&quot;** RECEIVING DATA **\n&quot;);
						}

						// check if the &quot;on&quot; or &quot;off&quot; bit tone is strongest
						if(dwStrongestToneType == BIT_TONE_FREQUENCY_ON)
						{
							// received &quot;1&quot; bit
							bGlobal_RecvBits[7 - (dwGlobal_BitsReceived % 8)] = 1;
						}
						else
						{
							// received &quot;0&quot; bit
							bGlobal_RecvBits[7 - (dwGlobal_BitsReceived % 8)] = 0;
						}

						// wait for confirmation before reading next bit
						dwGlobal_BitsReceived++;

						// check if a full byte (8 bits) has been received
						if(dwGlobal_BitsReceived % 8 == 0)
						{
							// convert bits to byte
							bRecvByte = 0;
							for(DWORD i = 0; i &lt; 8; i++)
							{
								// convert current bit
								bRecvByte |= (bGlobal_RecvBits[i] &lt;&lt; i);
							}

							// print current byte
							printf(&quot;%c&quot;, bRecvByte);
						}
					}
					else if(dwStrongestToneType == TRANSMISSION_END_FREQUENCY)
					{
						// end of transmission
						if(dwGlobal_BitsReceived != 0)
						{
							printf(&quot;\n** END OF TRANSMISSION (received %u bytes) **\n&quot;, dwGlobal_BitsReceived / 8);
						}
						dwGlobal_TransmissionStarted = 0;
					}
				}

				// store last tone type
				dwGlobal_LastToneType = dwStrongestToneType;
			}
		}
	}

	// update values for next chunk
	dwSamplesRemaining -= dwCurrChunkSize;
	dwCurrSampleIndex += dwCurrChunkSize;
}

return 0;

}

int main()
{
HWAVEIN hWave = NULL;
WAVEHDR WaveHeaderData;
WAVEFORMATEX WaveFormatData;
DWORD dwRetnVal = 0;
HANDLE hWaveEvent = NULL;

// create event
hWaveEvent = CreateEvent(NULL, 1, 0, NULL);
if(hWaveEvent == NULL)
{
	return 1;
}

// set wave format data
memset((void*)&amp;WaveFormatData, 0, sizeof(WaveFormatData));
WaveFormatData.wFormatTag = WAVE_FORMAT_PCM;
WaveFormatData.wBitsPerSample = AUDIO_BITS_PER_SAMPLE;
WaveFormatData.nChannels = 1;
WaveFormatData.nSamplesPerSec = AUDIO_SAMPLE_RATE;
WaveFormatData.nAvgBytesPerSec = AUDIO_BITS_PER_SAMPLE * (AUDIO_BITS_PER_SAMPLE / 8);
WaveFormatData.nBlockAlign = AUDIO_BITS_PER_SAMPLE / 8;                    
WaveFormatData.cbSize = 0;

// open wave handle
if(waveInOpen(&amp;hWave, WAVE_MAPPER, &amp;WaveFormatData, (DWORD)hWaveEvent, 0, CALLBACK_EVENT | WAVE_FORMAT_DIRECT) != MMSYSERR_NOERROR)
{
	CloseHandle(hWaveEvent);
	return 1;
}

for(;;)
{
	// set wave header data
	memset((void*)&amp;WaveHeaderData, 0, sizeof(WaveHeaderData));
	WaveHeaderData.lpData = (LPSTR)bGlobal_AudioBuffer;
	WaveHeaderData.dwBufferLength = sizeof(bGlobal_AudioBuffer);
	WaveHeaderData.dwBytesRecorded = 0;
	WaveHeaderData.dwUser = 0;
	WaveHeaderData.dwFlags = 0;
	WaveHeaderData.dwLoops = 0;

	// prepare wave header
	if(waveInPrepareHeader(hWave, &amp;WaveHeaderData, sizeof(WaveHeaderData)) != MMSYSERR_NOERROR)
	{
		// error
		CloseHandle(hWaveEvent);
		waveInClose(hWave);

		return 1;
	}

	// add wave input buffer
	if(waveInAddBuffer(hWave, &amp;WaveHeaderData, sizeof(WaveHeaderData)) != MMSYSERR_NOERROR)
	{
		// error
		CloseHandle(hWaveEvent);
		waveInClose(hWave);

		return 1;
	}

	// reset event
	ResetEvent(hWaveEvent);

	// start recording
	if(waveInStart(hWave) != MMSYSERR_NOERROR)
	{
		// error
		CloseHandle(hWaveEvent);
		waveInClose(hWave);

		return 1;
	}

	// wait until recording has finished
	for(;;)
	{
		// wait for event to fire
		WaitForSingleObject(hWaveEvent, INFINITE);

		// check if sample has finished recording
		if(WaveHeaderData.dwFlags &amp; WHDR_DONE)
		{
			// finished
			break;
		}
	}

	// unprepare wave header
	if(waveInUnprepareHeader(hWave, &amp;WaveHeaderData, sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
	{
		// error
		CloseHandle(hWaveEvent);
		waveInClose(hWave);

		return 1;
	}

	// process audio samples
	if(ProcessSamples() != 0)
	{
		// error
		CloseHandle(hWaveEvent);
		waveInClose(hWave);

		return 1;
	}
}

// close wave handle
waveInClose(hWave);

// close event
CloseHandle(hWaveEvent);

return 0;

}

Comments(0)

Join the discussion by logging into your account.

No comments yet. Be the first to comment!

I0veD
I0veD

cyber security researcher

Cloud Native & AI Sec Researcher Red Team | BAS | K8s | Evasion 20+ CVEs | CNVD/CNNVD Contributor 🛡️ AI-Driven Blue Team 👇 Works

Subscribe to I0veD's Newsletter

Direct email dispatches when new stories are published. Zero algorithms.