VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

Noisy Waves: TRNG virus

Valhalla #3
December 2012

[Back to index] [Comments]


It is uncommon to find viruses which use hardware enhancements. I heard of a virus which uses GPU to decipher its code. At the time I already knew about hh86's work on Intel AES-NI instruction set to assist AES encryption. It is common, however, to associate viruses and microphone devices in espionage. I present here another technique.

Reading you Five

PRN (PseudoRandom Number Generators) use mathematical algorithms to generate what would seem to be random numbers from a seed. But due to the fact that PRNG are deterministic at heart, every random number can be guessed from the base seed. Unlike PRNG, TRNG "True Random Number Generators" do not rely on such mathematical algorithms, so they cannot be safely predicted.

To generate TRNG there is hardware, but it can be too expensive, and hard to get. Finally, I found aresearch in The author uses background ambient/atmospheric noise. A good source for randomness. And of course, a cheaper alternative.

Windows has a set of API easy to use to play or record audio. MCI API is bit boring so I decided to use WaveForm API instead. We record as if we were to create WAV format audio file.

We will use just a few APIs, here is a sample code:

wave_formatex   label    near
        dw      WAVE_FORMAT_PCM                                     ;WAVEFORMATEX.wFormatTag (uncompressed data LPCM (linear pulse code modulation))
        dw      nChannels                                           ;WAVEFORMATEX.nChannels
        dd      nSamplesPerSec                                      ;WAVEFORMATEX.nSamplesPerSec
        dd      nSamplesPerSec * ((nChannels * wBitsPerSample) / 8) ;WAVEFORMATEX.nAvgBytesPerSec
        dw      (nChannels * wBitsPerSample) / 8                    ;WAVEFORMATEX.nBlockAlign
        dw      wBitsPerSample                                      ;WAVEFORMATEX.wBitsPerSample
        dw      0                                                   ;WAVEFORMATEX.cbSize = sizeof WAVEFORMATEX

wave_setup      label    near
        mov     edi, esp                     ;in stack - API addresses
        mov     ebx, ecx
        mov     ebp, (nSamplesPerSec * RecordingTimeSecs) * ((nChannels * wBitsPerSample) / 8) + sizeof WAVEHDR
        push    ebp
        push    40h
        call    dword ptr [edi + sizeof WINMM + KERNEL32.kGlobalAlloc]
        lea     ecx, dword ptr [eax + sizeof WAVEHDR]
        mov     dword ptr [eax + WAVEHDR.lpData], ecx
        mov     dword ptr [eax + WAVEHDR.dwBufferLength], ebp
        lea     edx, dword ptr [esi - (offset wave_setup - offset wave_formatex)]
        push    edi
        push    eax
        push    esi
        push    ebx
        mov     esi, esp
        xchg    ebp, eax
        push    sizeof WAVEHDR
        push    ebp
        push    sizeof WAVEHDR
        push    ebp
        push    WAVE_FORMAT_DIRECT
        push    ebx
        push    ebx
        push    edx
        push    WAVE_MAPPER
        push    esi
        call    dword ptr [edi + WINMM.waveInOpen]
        lods    dword ptr [esi]
        xchg    esi, eax
        push    esi
        call    dword ptr [edi + WINMM.waveInPreparedHeader]
        push    esi
        call    dword ptr [edi + WINMM.waveInAddBuffer]
        push    esi
        call    dword ptr [edi + WINMM.waveInStart]

waverec_loop    label     near
        push    sizeof WAVEHDR
        push    ebp
        push    esi
        call    dword ptr [edi + WINMM.waveInUnpreparedHeader]
        cmp     al, WAVERR_STILLPLAYING
        je      waverec_loop
        call    dword ptr [edi + WINMM.waveInClose]

First is to setup WAVEFORMATEX. Set FormatTag to be an uncompressed data LPCM input. Set channels to 2, so that it is stereo (or try 1 channel for mono). Samples per seconds, is set to 44.1Khz. Average bytes per second is calculated using number of samples per second multiplied by block alignment. Block alignment is calculated multiplying number of channels by number of bits for each sample per second, and dividing the result by 8.

Second is to setup WAVEHDR. Most fields are useless, and we ignore them all with exception of lpData which is pointer to a buffer to receive recording, and then buffer length.

Call waveInOpen to open the device for input, and let the function decide which device open because we haven't included any code to find one. If API returns MMSYSERR_NOERROR (0), it's okay, then you might want to check that it returned a handler. WAVEFORMATEX structure is of no use now.

Call waveInPrepareHeader to prepare buffer for input data. waveInAddBuffer, will send prepared buffer to input device. waveInStart will start input from device.

Finally try to clean up using waveInUnprepareHeader, if buffer is still in queue, keep trying. Once it succeeds, close device.

Roger That!

I strongly recommend you to not use this data to seed your PRNG. ;) My code uses recordings (if successful) as encryption key on simple XTEA.

(o) - gzgztt3/at/
By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! aka